Supervisor linking finished. New signup completed. Out cells in collections grid removed

parent f588d2e8
......@@ -155,7 +155,7 @@ module.exports = {
// Promisify asynchronous call to Student.supervisors
var supervisors = new Promise(function (resolve, reject) {
Student.supervisors(student.id, function (err, ss) {
Student.validSupervisors(student.id, req.token.id, function (err, ss) {
if (err) return reject(err);
return resolve(ss);
});
......@@ -335,7 +335,7 @@ module.exports = {
/**
* Return all existing supervisor and therapist from a given student
* Return all existing supervisors for a given student that are in our office
* @param {request} req {} (with studentId as url parameter)
* @param {response} res
* [
......@@ -363,81 +363,12 @@ module.exports = {
error: 'No student defined'
});
}
Student.supervisors(req.params.id_stu, function (err, sups) {
Student.validSupervisors(req.params.id_stu, req.token.id, function (err, sups) {
if (err) throw err;
return res.json(sups);
});
},
/**
* Return all existing therapists from a given student
* @param {request} req {} (with studentId as url parameter)
* @param {response} res
* [
* {
* id: therapistId,
* name: 'John',
* surname: 'Doe',
* gender: 'M/F',
* pic: 'supervisor/avatar.jpg',
* address: 'My Address, n1',
* country: 'ES',
* email: 'john@doe.es',
* phone: '+123123123',
* lang: 'es-es',
* active: true,
* ttsEngine: 'IVONA-Text',
* office: officeId
* },
* ...
* ]
*/
therapists: function (req, res) {
if (!req.params.id_stu) {
return res.json(500, {
error: 'No student defined'
});
}
Student.therapists(req.params.id_stu, function (err, sups) {
if (err) throw err;
return res.json(sups);
});
},
/**
* Return all existing tutors from a given student
* @param {request} req {} (with studentId as url parameter)
* @param {response} res
* [
* {
* id: tutorId,
* name: 'John',
* surname: 'Doe',
* gender: 'M/F',
* pic: 'supervisor/avatar.jpg',
* address: 'My Address, n1',
* country: 'ES',
* email: 'john@doe.es',
* phone: '+123123123',
* lang: 'es-es',
* active: true,
* ttsEngine: 'IVONA-Text',
* office: officeId
* },
* ...
* ]
*/
tutors: function (req, res) {
if (!req.params.id_stu) {
return res.json(500, {
error: 'No student defined'
});
}
Student.tutors(req.params.id_stu, function (err, sups) {
if (err) throw err;
return res.json(sups);
});
},
/**
* Creates a relation between the student and a given supervisor.
......@@ -898,28 +829,27 @@ module.exports = {
* @param {response} res {}
*/
getActiveScene: function(req, res){
if (typeof req.params.id_stu == 'undefined' || !req.params.id_stu)
return res.badRequest("id_stu not defined");
Student.findOne({id:req.params.id_stu}).then(function(student){
Scene.findOne({id: student.id_active_scene})
.then(function(scene){
if(!scene)
return res.badRequest("Scene not found");
else
Scene.pictos(scene.id, function(err, pictos){
if (err){
return res.serverError("Error obtaining pictos: "+ err);
}
scene.active = true;
scene.pictos=pictos;
return res.ok(scene);
});
}).catch(function (err){
return res.serverError("Error finding scene "+err);
});
}).catch(function(err){
return res.badRequest("Student not found");
if (typeof req.params.id_stu == 'undefined' || !req.params.id_stu)
return res.badRequest("id_stu not defined");
Student.findOne(req.params.id_stu)
.then(function(student) {
if (!student)
throw new Error("Student not found")
return Scene.findOne({id: student.id_active_scene});
})
.then(function(scene){
if(!scene)
throw new Error("Scene not found");
Scene.pictos(scene.id, function(err, pictos){
if (err)
return res.serverError("Error obtaining pictos: "+ err);
scene.active = true;
scene.pictos=pictos;
return res.ok(scene);
});
}).catch(function(err){
return res.badRequest(err.message);
});
},
/**
......
......@@ -198,15 +198,54 @@ module.exports = {
* }
*/
getByEmail: function (req, res) {
Supervisor.findOne({ email: req.params.email }).then(function (supervisor) {
if (supervisor) {
res.ok(supervisor);
} else {
res.notFound();
}
// Find supervisor
Supervisor.findOne({ email: req.params.email })
.then((s) => {
if (!s)
throw new Error("Not found");
res.ok(s);
})
.catch(function () {
res.serverError();
.catch(function (err) {
res.serverError(err);
});
},
/**
* Gets a supervisor by his email (only those that are related to us)
* @param {request} req {} (width email as url parameter)
* @param {response} res
* {
* "name": "John"
* "surname": "Doe"
* "gender": "F/M"
* "password": "1234"
* "pic": "url/to/photo.jpg"
* "address": "Nice street"
* "country": "ES/UK/..."
* "email": "john@doe.com"
* "phone": "+123456789"
* "lang": "ES/EN/..."
* "ttsEngine: "IVONA Text-to-Speech HQ"
* }
*/
getFromOfficeByEmail: function (req, res) {
// Find supervisor
Supervisor.findOne({ email: req.params.email })
.then((s) => {
if (!s)
throw new Error("Not found");
// Check is in our office
return SupOff.findOne({supervisor: s.id, office: req.token.id}).populate('supervisor');
})
.then((so) => {
if (!so)
throw new Error("Not in our office");
res.ok(so.supervisor);
})
.catch(function (err) {
res.serverError(err);
});
},
......@@ -512,19 +551,32 @@ module.exports = {
// Check that both ids are valid
Supervisor.findOne(req.params.id_sup)
.then((s) => {
if (!s)
throw new Error("Supervisor not found");
return Supervisor.findOne(req.params.id_off);
}).then((s) => {
if (!s)
.then((sup) => {
if (!sup)
throw new Error("Supervisor not found");
return SupOff.create({supervisor: req.params.id_sup, office: req.params.id_off});
return [sup, Supervisor.findOne(req.params.id_off)];
})
.then((so) => {
.spread((sup, off) => {
if (!off)
throw new Error("Office not found");
return [sup, off, SupOff.create({supervisor: sup.id, office: off.id})];
})
.spread((sup, off, so) => {
if (!so)
throw new Error("Unable to perform linking");
res.ok();
console.log("SUP.LANG:" + sup.lang);
// An notification is sent to added supervisor
mailService.mailer()
.send({
to: sup.email,
text: sails.__({
phrase: 'office_link',
locale: sup.lang || 'es-es'
}, {name: off.name, email: off.email})
})
.then(() => {res.ok()})
.catch((err) => {throw err});
})
.catch((err) => {
res.badRequest(err.message);
......
......@@ -289,49 +289,56 @@ module.exports = {
},
//
// Class method for getting the list of supervisors (therapist + tutors) associated to a given
// student
supervisors: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
if (err)
return callback(err, []);
// Class method for getting the list of supervisors associated to a given
// student and where the requester is related office
validSupervisors: function(id_stu, id_sup, callback) {
// Get all supervisors
StuSup.find({id_stu: id_stu})
.populate('supervisor')
.then((stuSups) => {
if (!stuSups || stuSups.length == 0)
return callback(null, []);
throw new Error("No supervisors");
// filter null entries and map them to the supervisor object
var sups = _.compact(stuSups).map((st) => {return st.supervisor});
return callback(null, sups);
});
},
// return supervisors and related supervisors to the office
return [stuSups, SupOff.find({office: id_sup}).populate('supervisor')]
})
.spread((stuSups, supOffs) => {
//
// Class method for getting the list of therapists associated to a given
// student
therapists: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
var l = [];
if (!supOffs || supOffs.length == 0)
throw new Error("No supervisors");
if (err || !stuSups || stuSups.length == 0)
return callback(err, l);
// filter null entries and map them to the supervisor object
var ss = _.compact(_.compact(stuSups).map(x => x.supervisor));
var so = _.compact(_.compact(supOffs).map(x => x.supervisor));
// filter from the second list those found in the first list
var sups = so.filter(a => ss.findIndex(b => b.id == a.id) >= 0);
var sups = _.compact(stuSups).filter((st) => {st.supervisor && st.supervisor.role == 'therapist'});
return callback(null, sups);
})
.catch((err) => {
return callback(err, []);
});
},
//
// Class method for getting the list of tutors associated to a given
// Class method for getting the list of all the supervisors associated to a given
// student
tutors: function(id_stu, callback) {
StuSup.find({id_stu: id_stu}).populate('supervisor').exec(function(err, stuSups) {
var l = [];
if (err || !stuSups || stuSups.length == 0)
return callback(err, l);
allSupervisors: function(id_stu, callback) {
var sups = _.compact(stuSups).filter((st) => {st.supervisor && st.supervisor.role == 'tutor'});
return callback(null, sups);
// Get all supervisors
StuSup.find({id_stu: id_stu})
.populate('supervisor')
.then((stuSups) => {
if (!stuSups || stuSups.length == 0)
throw new Error("No supervisors");
var ss = _.compact(stuSups).map(x => x.supervisor);
return callback(null, ss);
})
.catch((err) => {
return callback(err, []);
});
},
......
......@@ -9,7 +9,7 @@ module.exports = function isStudentOrSupervisorOfStudent (req, res, next) {
return next();
// Get list of supervisors for the student
Student.supervisors(req.params.id_stu, function(err, sups) {
Student.allSupervisors(req.params.id_stu, function(err, sups) {
if (err)
return res.json(401, {error: err});
......
......@@ -7,7 +7,7 @@ module.exports = function isSupervisorOfStudent(req, res, next) {
// Get list of supervisors for the student
Student.supervisors(req.params.id_stu, function(err, sups) {
Student.allSupervisors(req.params.id_stu, function(err, sups) {
if (err)
return res.json(401, {error: err});
......
......@@ -419,7 +419,9 @@
"sup_not_added": "Supervisor not added to the student",
"sup_not_deleted": "The supervisor couldn't be deleted by the student",
"sup_not_found": "There is no supervisor account in Pictogram with this email",
"sup_not_in_office": "There is no supervisor account related to your office/center with this email.",
"supervisor_added": "Supervisor added",
"supervisor_added_notified": "Supervisor added. A notification email has been sent to his/her email address.",
"supervisor_already_linked": "The supervisor is already linked to your account",
"supervisor_deleted": "Supervisor deleted",
"supervisor_not_added": "Supervisor not added",
......@@ -460,6 +462,7 @@
"tries_per_instruction_method": "Tries per instruction of method",
"tries_per_months": "Tries per months in",
"tries_results_instruction": "Tries results in instruction",
"tutor": "Parent/tutor",
"tutor_added": "Tutor added to the student",
"tutor_account_desc": "Manage child's pictograms and configure his/her communication device.",
"tutor_deleted": "Tutor removed from the student",
......
......@@ -79,8 +79,7 @@
"close_session": "Cerrar sesion",
"collections": "Colecciones",
"confirmation": "¿Estás seguro?",
"confirm_unlink_therapist": "¿Desligar {{ name }} de {{ student }} como terapeuta?",
"confirm_unlink_tutor": "¿Desligar {{ name }} de {{ student }} como tutor?",
"confirm_unlink_student": "¿Desligar {{ name }} de {{ student }}?",
"contact_person": "Persona de contacto",
"contact_person": "Persona de contacto",
"continue_session": "Reanudar sesión",
......@@ -263,7 +262,8 @@
"no_method": "Método sin definir",
"no_office": "Sin centro",
"no_instruction": "Instrucción sin definir",
"no_students_for_user": "Su cuenta no está asociada a ningún estudiante. Por favor, contacte con su gabinete para enlazar su cuenta a un estudiante.",
"no_students": "Su cuenta no está asociada a ningún estudiante",
"no_students_desc": "Pulse en 'Añadir estudiante' para vincularse a cuentas de alumnos existentes o dar de alta nuevas",
"no_space_in_category": "No queda espacio en la categoría",
"no_subscribed": "Sin conexión a la cuenta del estudiante",
"no_supervisors": "No tiene tutores, padres o terapeutas asociados.",
......@@ -419,7 +419,9 @@
"sup_not_added": "El supervisor no se ha podido añadir al estudiante.",
"sup_not_deleted": "El supervisor no se ha podido desvincular del alumno.",
"sup_not_found": "No hay ningún usuario en Pictogram con ese correo electrónico.",
"sup_not_in_office": "No hay ningún usuario asociado a su centro/gabinete con ese correo electrónico.",
"supervisor_added": "Supervisor añadido",
"supervisor_added_notified": "Supervisor añadido. Se le ha enviado al mismo una notificación por correo electrónico.",
"supervisor_already_linked": "El supervisor ya está vinculado",
"supervisor_deleted": "Supervisor eliminado",
"supervisor_not_added": "Supervisor no añadido",
......@@ -460,6 +462,7 @@
"tries_per_instruction_method": "Ensayos por instrucción del método",
"tries_per_months": "Número de ensayos por meses en",
"tries_results_instruction": "Resultados ensayos en instrucción",
"tutor": "Padre/madre/tutor",
"tutor_account_desc": "Gestione los pictogramas de su hijo o hija y configure su dispositivo de comunicación.",
"tutor_added": "Tutor añadido al estudiante",
"tutor_deleted": "Tutor desvinculado del estudiante",
......
......@@ -26,7 +26,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
});*/
$scope.supsForm = {};
$scope.section = 'account';
$scope.section = {val: 'account'};
$scope.changeImg = function () {
......@@ -148,11 +148,11 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
.error(function (err) {
console.log(err);
if (err.message && err.message.search('nvalid license') > 0)
ngToast.danger({ content: $translate.instant('license_invalid') });
ngToast.danger($translate.instant('license_invalid'));
else if (err.message && err.message.search('in use') > 0)
ngToast.danger({ content: $translate.instant('license_already_activated') });
ngToast.danger($translate.instant('license_already_activated'));
else
ngToast.danger({ content: $translate.instant('student_not_updated') });
ngToast.danger($translate.instant('student_not_updated'));
});
};
......@@ -161,26 +161,21 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
* The email used for search is fetched from $scope.email_sup.
*/
$scope.search_sup = function () {
console.log("--> " + $scope.supsForm.email_sup);
// Find tutor by email
$http.get(config.backend + '/sup/email/' + $scope.supsForm.email_sup)
$http.get(config.backend + '/sup/off/email/' + $scope.supsForm.email_sup)
.success(function (data) {
if (data) {
$scope.supToAdd = data;
$scope.showmessagesupfound = true;
$scope.showmessagesupnotfound = false;
} else {
$translate('sup_not_found').then(function (translation) {
ngToast.danger({ content: translation });
});
ngToast.danger($translate.instant('sup_not_in_office'));
// Hide the success message (if it exists by other query)
$scope.showmessagesupfound = false;
}
})
.error(function () {
$translate('sup_not_found').then(function (translation) {
ngToast.danger({ content: translation });
});
ngToast.danger($translate.instant('sup_not_in_office'));
});
};
......@@ -193,13 +188,13 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
// Ensure supervisor is not already in the list
if ($scope.studentSupervisors.map((s) => s.id).includes($scope.supToAdd.id)) {
ngToast.danger({ content: $translate.instant('sup_already_added') });
ngToast.danger($translate.instant('sup_already_added'));
$scope.supsForm.email_sup = '';
$scope.showmessagesupfound = false;
return;
}
$http.post(config.backend + '/stu/' + $scope.studentData.id + '/sup/' + $scope.supToAdd.id, {asTherapist: true})
$http.post(config.backend + '/stu/' + $scope.studentData.id + '/sup/' + $scope.supToAdd.id)
.success(function (data) {
// Assign the info of supervisor to add
stusup.supervisor = $scope.supToAdd;
......@@ -214,7 +209,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
$scope.showmessagesupfound = false;
})
.error(function () {
ngToast.danger({ content: $translate.instant('sup_not_added') });
ngToast.danger($translate.instant('sup_not_added'));
});
};
......@@ -226,7 +221,7 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
var deleteSup = $window.confirm(
$translate.instant(
'confirm_unlink_therapist',
'confirm_unlink_student',
{name: $scope.studentSupervisors[i].name, student: $scope.studentData.name}
));
......@@ -243,95 +238,6 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
}
};
// Search tutor by email
$scope.search_tutor = function () {
// Find tutor by email
$http.get(config.backend + '/sup/email/' + $scope.supsForm.email_tutor)
.success(function (data) {
// If it found the length is > 0
if (data) {
$scope.tutorToAdd = data;
// Show message for validate
$scope.showmessagetutorfound = true;
$scope.showmessagetutornotfound = false;
} else {
$translate('tutor_not_found').then(function (translation) {
ngToast.danger({ content: translation });
});
// Hide the success message (if it exists by other query)
$scope.showmessagetutorfound = false;
}
})
.error(function () {
$translate('tutor_not_found').then(function (translation) {
ngToast.danger({ content: translation });
});
});
};
// Add tutor
$scope.add_tutor = function () {
var stusup = {
student: $scope.studentData.id,
supervisor: $scope.tutorToAdd.id
};
// Ensure supervisor is not already in the list
if ($scope.studentTutors.map((s) => s.id).includes($scope.tutorToAdd.id)) {
ngToast.danger({ content: $translate.instant('sup_already_added') });
$scope.supsForm.email_tutor = '';
$scope.showmessagetutorfound = false;
return;
}
$http.post(config.backend + '/stu/' + $scope.studentData.id + '/sup/' + $scope.tutorToAdd.id)
.success(function (data) {
// Assign the info of supervisor to add
stusup.supervisor = $scope.tutorToAdd;
stusup.id = data.id;
// Add to the list of tutors in view
$scope.studentTutors.push($scope.tutorToAdd);
// Delete the email form field
$scope.supsForm.email_tutor = '';
// Hide the message of tutor founded
$scope.showmessagetutorfound = false;
$translate('tutor_added').then(function (translation) {
ngToast.success({ content: translation });
});
})
.error(function () {
$translate('tutor_not_added').then(function (translation) {
ngToast.danger({ content: translation });
});
});
};
// Delete tutor
$scope.delete_tutor = function (id_sup) {
//Se recorre el array de objetos json para buscarlo
var i;
for (i = 0; i < $scope.studentTutors.length && id_sup !== $scope.studentTutors[i].id; i++);
var deleteTutor = $window.confirm(
$translate.instant(
'confirm_unlink_tutor',
{name: $scope.studentTutors[i].name, student: $scope.studentData.name}
));
if (deleteTutor) {
$http.delete(config.backend + '/stu/' + $scope.studentData.id + '/sup/' + id_sup)
.success(function () {
// Eliminar de la vista
$scope.studentTutors.splice(i, 1);
ngToast.success({ content: $translate.instant('tutor_deleted') });
})
.error(function () {
ngToast.danger({ content: $translate.instant('tutor_not_deleted') });
});
}
};
// *******************************************************
// Setup
// $scope.studentData.attributes
......@@ -342,14 +248,10 @@ dashboardControllers.controller('StudentSetupCtrl', function StudentSetupCtrl(
attributes: $scope.studentData.attributes
})
.success(function () {
$translate('attributes_updated').then(function (translation) {
ngToast.success({ content: translation });
});
ngToast.success($translate.instant('attributes_updated'));
})
.error(function () {
$translate('attributes_not_updated').then(function (translation) {
ngToast.danger({ content: translation });
});
ngToast.danger($translate.instant('attributes_not_updated'));
});
}, 300);
});
......@@ -83,11 +83,11 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
};
// ----------------------------------------------------------------------
// MAIN
//
// Load student account information
//
//
$http.get(config.backend + '/stu/' + $scope.studentData.id)
.success(function (data) {
$scope.studentData.id = data.id;
......@@ -141,27 +141,22 @@ dashboardControllers.controller('StudentCtrl', function StudentCtrl(
ngToast.danger({ content: $translate.instant('no_subscribed') });
});
//
// For tab navigation, initially blank goes to collections
// Defined as JSON object to be available in in children as the same scope
//
$scope.nav = {
tab: 'collections'
};
//
// Load student supervisors
//
$scope.studentSupervisors = [];
$http.get(config.backend + '/stu/' + $scope.studentData.id + '/therapists')
$http.get(config.backend + '/stu/' + $scope.studentData.id + '/supervisors')
.success(function (data) {
$scope.studentSupervisors = data;
})
.error(function () {
// TODO show error with ngToast
});
.error(function (err) {});
$scope.studentTutors = [];
$http.get(config.backend + '/stu/' + $scope.studentData.id + '/tutors')
.success(function (data) {
$scope.studentTutors = data;
})
.error(function () {
// TODO show error with ngToast
});
});
......@@ -25,7 +25,8 @@
ng-init="rowIndex = $index"
class="picto-grid__row">
<div
class="picto pull-left ng-class:{'picto-out': studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)};"
ng-hide="studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)"
class="picto pull-left"
data-row="{{ rowIndex }}"
data-column="{{ colIndex }}"
id="student-picto-{{
......@@ -117,7 +118,8 @@
ng-init="rowIndex = $index"
class="picto-grid__row">
<div
class="picto pull-left ng-class:{'picto-out': studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)};"
ng-hide="studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)"
class="picto pull-left"
ng-repeat="studentPicto in studentPictoRow track by $index"
ng-init="colIndex = $index"
popover="{{ studentPicto != emptyStudentPicto ? studentPicto.attributes.expression : ''}}"
......@@ -231,7 +233,8 @@
ng-init="rowIndex = $index"
class="picto-grid__row">
<div
class="picto pull-left ng-class:{'picto-out': studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)};"
ng-hide="studentData.attributes.size == 'large' && (rowIndex > 3 || colIndex > 7)"
class="picto pull-left"
data-row="{{ rowIndex }}"
data-column="{{ colIndex }}"
id="student-picto-{{
......
......@@ -51,7 +51,7 @@
<div class="col-md-12">
<ul class="nav nav-tabs tabs_student">
<!-- 0: admin, 1: tutor, 2: therapist -->
<li role="presentation" ng-class="{'active' : nav.tab == 'collections'}" ng-if="studentData.license.isValid && !studentData.license.isTrial">
<li role="presentation" ng-class="{'active' : nav.tab == 'collections'}" ng-if="studentData.license.isValid || !studentData.license.isTrial">
<a href="/app/#/student/{{studentData.id}}/collections" ng-click="nav.tab = ''"><span class="glyphicon glyphicon-th" aria-hidden="true"></span> {{ 'collections' | translate }}</a>
</li>
<li role="presentation" ng-class="{'active' : nav.tab == 'instructions'}" ng-if="studentData.license.isValid && !user.isTutor">
......
......@@ -2,18 +2,21 @@
<div class="panel-body">
<div class="btn-group">
<button class="btn btn-default" btn-radio="'account'" ng-model="section">
<button class="btn btn-default" btn-radio="'account'" ng-model="section.val">
<i class="fa fa-user" aria-hidden="true"></i> {{ 'account' | translate }}
</button>
<button class="btn btn-default" btn-radio="'device'" ng-model="section" ng-if="studentData.license.isValid || studentData.license.isOfficial">
<button class="btn btn-default" btn-radio="'device'" ng-model="section.val" ng-if="studentData.license.isValid || studentData.license.isOfficial">
<i class="fa fa-tablet" aria-hidden="true"></i> {{ 'device' | translate }}
</button>
<button class="btn btn-default" btn-radio="'supervisors'" ng-model="section" ng-if="user.isOffice">
<button class="btn btn-default" btn-radio="'supervisors'" ng-model="section.val" ng-if="user.isOffice">
<i class="fa fa-users" aria-hidden="true"></i> {{ 'supervisors' | translate }}
</button>
</div>
<div class="row" ng-show="section == 'account'">
<!-- ***********************************************************************
Sección: Configuración de la cuenta del estudiante
-->
<div class="row" ng-show="section.val == 'account'">
<!-- Parte izquierda: Datos personales -->
<div class="col-md-6">
<legend translate>account</legend>
......@@ -187,9 +190,12 @@
</div> <!-- Fin de student_personal_edit -->
<!-- ***********************************************************************
Sección: Configuración del dispositivo
-->
<!-- Configuración dispositivo -->
<div id="device_setup" ng-show="section == 'device'">
<div id="device_setup" ng-show="section.val == 'device'">
<div class="row">
<div class="col-md-6">
<legend translate>device_setup</legend>
......@@ -325,14 +331,28 @@
</div>
</div>
<!-- ***********************************************************************
Sección: Gestión de supervisores
-->
<!-- Tutores y dispositivos -->
<div id="supervisors_section" ng-show="section == 'supervisors'">
<div id="supervisors_section" ng-show="section.val == 'supervisors'" ng-if="user.isOffice">
<legend translate>link_supervisor</legend>
<div class="row">
<div class="col-md-5" ng-if="user.isOffice">
<div class="col-md-5">
<div class="alert alert-info">
<p translate>link_supervisor_desc</p>
<p translate>supervisor_note</p>
</div>
</div>
<div class="col-md-5">
<!-- Supervisores (terapeutas) del alumno -->
<div id="student_sups">
<legend translate>therapists</legend>
<!-- Buscador de supervisores -->
<p>
<form role="search" ng-submit="search_sup()">
......@@ -353,71 +373,34 @@
<img ng-src="{{supToAdd.pic}}" class="profile" alt="" title="" /> {{ supToAdd.name }} {{ supToAdd.surname }}
<a class="btn btn-default btn-sm pull-right" role="button" ng-click="add_sup()" translate>add</a>
</div>
<!-- Fin de buscador de supervisores -->
<!-- Supervisores asignados -->
<ul class="list-group" id="user_sups">
<li class="list-group-item" ng-repeat="sup in studentSupervisors">
<!-- Imagen de perfil del supervisor -->
<img ng-src="{{sup.pic}}" class="profile" alt="" title="" />
{{sup.name}} {{sup.surname}}
<a ng-click="delete_sup(sup.id)" class="delete_sup" title="{{ 'unlink' | translate}}">
<span class="color_red glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</a>
</li>
</ul>
<!-- Fin de Supervisores asignados -->
</div>
<!-- Fin de id student-sups -->
</div>
<div class="col-md-5">
<!-- Tutores (Padres) -->
<div id="student_tutors" ng-if="user.isOffice">
<legend translate>tutors</legend>
<!-- Buscador de tutores -->
<p>
<form role="search" ng-submit="search_tutor()">
<div class="input-group">
<input type="email" class="form-control" placeholder="{{ 'search_tutor_email' | translate }}" name="email_tutor" id="email_tutor" ng-model="supsForm.email_tutor" required>
<div class="input-group-btn">
<button class="btn btn-default" type="submit">
<span class="glyphicon glyphicon-search"></span>
</button>
<div class="row">
<div class="col-xs-2">
<!-- Imagen de perfil del supervisor -->
<img ng-src="{{sup.pic}}" class="profile" alt="" title="" />
</div>
<div class="col-xs-8">
{{ sup.name }} {{ sup.surname }} <br> <span class="text-muted">{{ sup.role | translate }}</span>
</div>
<div class="col-xs-2">
<a ng-click="delete_sup(sup.id)" class="delete_sup" title="{{ 'unlink' | translate}}">
<span class="color_red glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</a>
</div>
</div>
</form>
</p>
<!-- Alert and success messages for tutor found -->
<div ng-show="{{ 'showmessagetutorfound' }}" class="alert alert-info">
<!-- Imagen de perfil del tutor -->
<img ng-src="{{tutorToAdd.pic}}" class="profile" alt="" title="" />
{{ tutorToAdd.name }} {{ tutorToAdd.surname }}
<a class="btn btn-default btn-sm pull-right" role="button" ng-click="add_tutor()" translate>add</a>
</div>
<!-- Fin de buscador de tutores -->
<!-- Tutores asignados -->
<ul class="list-group" id="user_tutors">
<li class="list-group-item" ng-repeat="tutor in studentTutors">
<!-- Imagen de perfil del tutor -->
<img ng-src="{{tutor.pic}}" class="profile" alt="" title="" />
{{tutor.name}} {{tutor.surname}}
<a ng-click="delete_tutor(tutor.id)" class="delete_tutor" title="{{ 'unlink' | translate}}">
<span class="color_red glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</a>
</li>
</ul>
<!-- Fin de Tutores asignados -->
<!-- Info message -->
<div class="alert alert-info">{{ 'supervisor_note' | translate }}</div>
<!-- Fin de Supervisores asignados -->
</div>
<!-- Fin de id student-tutors -->
<!-- Fin de id student-sups -->
</div>
</div>
</div> <!-- /supervisores -->
</div>
<!-- Fin de panel body -->
</div>
......
......@@ -56,13 +56,6 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
}
};
// calendar function
$scope.open_calendar = function ($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened_cal_student = true;
};
// Show student form
$scope.showForm = function () {
// Reset the form
......@@ -103,14 +96,7 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
// Send link call to server
$http.post(config.backend + '/stu/license/sup/' + $scope.user.id, {license: $scope.formdata.license_number})
.success(function (data) {
ngToast.success({ content: $translate.instant('student_added') });
// default values
data.current_method = $translate.instant('no_method');
data.current_instruction = $translate.instant('no_instruction');
data.licenseIsValid = new Date(data.license.expiration_ts) - new Date() > 0 ? true : false;
$scope.students.push(data);
loadStudents();
$scope.slide.rightTo('confirmation');
})
.error(function (err) {
......@@ -146,15 +132,7 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
// Send creating call to server
$http.post(config.backend + '/stu', $scope.formdata)
.success(function (data) {
ngToast.success({ content: $translate.instant('student_added') });
// default values
data.supervision = 0; // by default, only related to office administrator
data.current_method = $translate.instant('no_method');
data.current_instruction = $translate.instant('no_instruction');
data.licenseIsValid = new Date(data.license.expiration_ts) - new Date() > 0 ? true : false;
$scope.students.push(data);
loadStudents();
$scope.slide.rightTo('confirmation');
})
.error(function (err) {
......@@ -179,14 +157,16 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
// Students list
// --------------------------------------------------------
// Get list of supervisor's students
$http.get(config.backend + '/sup/' + $scope.user.id + '/students')
.success(function (data) {
$scope.students = data;
})
.error(function () {
ngToast.danger({ content: $translate.instant('error_fetching_students') });
});
function loadStudents() {
// Get list of supervisor's students
$http.get(config.backend + '/sup/' + $scope.user.id + '/students')
.success(function (data) {
$scope.students = data;
})
.error(function () {
ngToast.danger({ content: $translate.instant('error_fetching_students') });
});
}
/**
* Unlink Student
......@@ -242,4 +222,8 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
});
}
});
// Main
loadStudents();
});
......@@ -69,7 +69,7 @@ dashboardControllers.controller('SupervisorsCtrl', function SupervisorsCtrl($sco
.post(config.backend+'/sup/' + $scope.supToAdd.id + '/off/' + $scope.user.id)
.success(function(data, status, headers, config) {
loadSupervisors();
ngToast.success($translate.instant('supervisor_added'));
ngToast.success($translate.instant('supervisor_added_notified'));
})
.error(function(error) {
var message = typeof error == 'string' ? error : error.message;
......
<!-- InstructionsCtrl controls here, see app.js -->
<div class="panel panel-default">
<div class="panel-heading"><h3 translate>own_instructions</h3></div>
<div class="panel-body">
<div class="row">
<div class="col-sm-6">
<!-- Select to add new method -->
<div class="form-group">
<!-- Botón añadir método -->
<button ng-click="add_method()" class="btn btn-success btn-sm" popover="{{ 'add' | translate }}" popover-trigger="mouseenter">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> <span translate>new_method</span>
</button>
</div>
</div>
<div class="col-sm-6 text-right" ng-if="!minimalMode">
<button class="btn btn-primary" ng-click="enable_minimal()"><i class="fa fa-eye-slash" aria-hidden="true"></i> Ver menos detalles</button>
</div>
<div class="col-sm-6 text-right" ng-if="minimalMode">
<button class="btn btn-primary" ng-click="enable_minimal()"><i class="fa fa-eye" aria-hidden="true"></i> Ver todo</button>
</div>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<div class="row">
<div class="col-xs-4">
<h3 translate>own_instructions</h3>
</div>
<div class="col-xs-4 margin-top20">
<div class="form-group">
<!-- Botón añadir método -->
<button ng-click="add_method()" class="btn btn-success btn-sm" popover="{{ 'add' | translate }}" popover-trigger="mouseenter">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> <span translate>new_method</span>
</button>
</div>
</div>
</div>
</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-12 text-right" ng-if="!minimalMode">
<button class="btn btn-primary" ng-click="enable_minimal()"><i class="fa fa-eye-slash" aria-hidden="true"></i> Ver menos detalles</button>
</div>
<div class="col-sm-12 text-right" ng-if="minimalMode">
<button class="btn btn-primary" ng-click="enable_minimal()"><i class="fa fa-eye" aria-hidden="true"></i> Ver todo</button>
</div>
</div>
<!-- Method instructions -->
<div class="method" ng-repeat="m in methods">
......
<!-- StudentsCtrl controls here, see app.js -->
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading"><h3 class="color-green" translate>students</h3>
<!-- span ng-if="user.isAdmin">({{user.office.currentStudents}}/{{user.office.maxStudents}} - <span translate="licenses_left" translate-values="{number: num_licenses_left}"></span>)</span -->
<div class="panel-body">
<!-- StudentsCtrl controls here, see app.js -->
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<div class="row">
<div class="col-xs-4">
<h3 translate>students</h3>
</div>
<div class="col-xs-4 margin-top20">
<!-- Add Student Form -->
<div ng-include="'modules/supervisor/views/students_add.html'" hidden="true" id="addform"></div>
<p class="text-left" ng-hide="slide.show">
<a ng-click="showForm()" class="btn btn-success btn-sm" role="button">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> {{ 'add_student' | translate }}
</a>
</p>
<!-- Add Student button and Search row -->
<div class="row">
<div class="col-xs-3">
<p class="text-left" ng-hide="slide.show">
<a ng-click="showForm()" class="btn btn-success btn-sm" role="button">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> {{ 'add_student' | translate }}
</a>
</p>
</div>
<div class="col-xs-6 input-group">
<p class="text-left" ng-show="slide.show">
<a ng-click="hideForm()" class="btn btn-danger btn-sm" role="button">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> {{ 'close' | translate }}
</a>
</p>
</div>
<div class="col-xs-4 margin-top20">
<div class=" input-group">
<input type="text" ng-model="search_students" id="search_students" placeholder="{{ 'filter' | translate }}" class="form-control" aria-describedby="basic-addon2">
<span class="input-group-addon"><span class="glyphicon glyphicon-search" id="basic-addon2" aria-hidden="true"></span></span>
</div>
<div class="col-xs-3">
</div>
</div>
</div>
<!-- Fin .panel-body -->
</div>
<!-- Add Student Form -->
<div ng-include="'modules/supervisor/views/students_add.html'" hidden="true" id="addform"></div>
</div>
<!-- Fin .panel-body -->
<!-- Table -->
<div ng-show="students.length == 0">
{{ no_students_for_user | translate }}
</div>
<div class="table-responsive">
<table id="table_students" class="table table-hover">
<tr ng-repeat="student in students | filter:search_students | orderBy: ['surname', 'name']">
<td>
......@@ -110,5 +116,11 @@
</td>
</tr>
</table>
<div class="alert alert-warning" ng-if="students.length == 0">
<strong translate>no_students</strong>. {{ 'no_students_desc' | translate }}.
</div>
</div>
<!-- Fin de row -->
<div class="row">
<div class="col-xs-3">
<p class="text-left">
<a ng-click="hideForm()" class="btn btn-danger btn-sm" role="button">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> {{ 'close' | translate }}
</a>
</p>
</div>
<div class="col-xs-9"></div>
</div>
<div class="switch-panel-body height400" ng-switch="slide.state">
......
......@@ -9,7 +9,11 @@
<div class="col-xs-4 margin-top20">
<div class=" input-group">
<input type="text" ng-model="inputs.email" placeholder="{{ 'email' | translate }}" class="form-control">
<span class="input-group-btn"> <button ng-click="searchSup()" class="btn btn-success btn-sm" role="button"> {{ 'link_supervisor' | translate }}</button></span>
<span class="input-group-btn" popover="{{ 'link_supervisor_desc' | translate }}" popover-trigger="mouseenter">
<button ng-click="searchSup()" class="btn btn-success btn-sm" role="button">
{{ 'link_supervisor' | translate }}
</button>
</span>
</div>
<!-- Alert and success messages for supervisor found -->
......
......@@ -8,5 +8,6 @@
"therapist_office_request": "{{ name }}, with email {{ email }}, is requesting to be linked as therapist to any of your students.",
"tutor_office_request": "{{ name }}, with email {{ email }}, is requesting to be linked as tutor/father/mother to any of your students.",
"welcome_msg1": "Welcome to Pictogram, {{ name }}!",
"welcome_msg2": "Your account is now active. You can proceed to"
"welcome_msg2": "Your account is now active. You can proceed to",
"office_link": "The office/center \"{{ name }}\" with email \"{{ email }}\" has added you as part of its team in Pictogram."
}
......@@ -8,5 +8,6 @@
"therapist_office_request": "El/la terapeuta {{ name }}, con correo electrónico {{ email }}, pide ser asociado a algún estudiante.",
"tutor_office_request": "El/la tutor/a/padre/madre {{ name }}, con correo electrónico {{ email }}, pide ser asociado a algún estudiante.",
"welcome_msg1": "¡Bienvenido a Pictogram, {{ name }}!",
"welcome_msg2": "Su cuenta está ahora activa, por lo que puede"
"welcome_msg2": "Su cuenta está ahora activa, por lo que puede",
"office_link": "El centro/gabinete \"{{ name }}\", con correo electrónico \"{{ email }}\" le ha añadido como parte de su equipo."
}
......@@ -138,7 +138,8 @@ module.exports.policies = {
list: ['tokenAuth', 'isAdmin'],
students: ['tokenAuth'],
pictos: ['tokenAuth'],
getByEmail: ['tokenAuth'],
getByEmail: ['tokenAuth', 'isOffice'],
getFromOfficeByEmail: ['tokenAuth', 'isOffice'],
update: ['tokenAuth'],
create: true,
login: true,
......
......@@ -82,8 +82,6 @@ module.exports.routes = {
'GET /stu/:id_stu': 'StudentController.getInfo',
'GET /stu/:id_stu/supervisors': 'StudentController.supervisors',
'GET /stu/:id_stu/therapists': 'StudentController.therapists',
'GET /stu/:id_stu/tutors': 'StudentController.tutors',
'POST /stu/license/sup/:id_sup': "StudentController.link_supervisor",
'POST /stu/:id_stu/sup/:id_sup': 'StudentController.link_supervisor',
'GET /stu/:id_stu/pictos': 'StudentController.pictos',
......@@ -127,6 +125,7 @@ module.exports.routes = {
'GET /sup/:id/pictos': 'SupervisorController.pictos',
'GET /sup/email/:email': 'SupervisorController.getByEmail',
'GET /sup/off/email/:email': 'SupervisorController.getFromOfficeByEmail',
'GET /sup/changepass/:email': 'SupervisorController.request_change_password',
'GET /sup/arasaac_license/:id': 'SupervisorController.accept_arasaac',
'PUT /sup/changepass': 'SupervisorController.change_password',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment