github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/frontend/bv/src/pages/espace_perso/logic/controller.ts (about) 1 import { BaseController } from "@/shared/logic/controller"; 2 import { 3 Aide, 4 CampPlus, 5 Participant, 6 Personne, 7 PublicDocument, 8 SchemaPaiement, 9 StatutAttente, 10 Sexe, 11 MessageKind, 12 ContenuSondage, 13 PseudoMessage 14 } from "@/shared/logic/types"; 15 import { age } from "../../../shared/logic/utils"; 16 import { Data } from "./data"; 17 18 // ATTENTION : cet app suppose qu'elle est déployée sur une url de la forme 19 // origin/espace_perso/<key> 20 21 export interface CompletionFicheSanitaire { 22 medecinNoms: string[]; 23 medecinTels: string[]; 24 telsAdditionnels: string[]; 25 } 26 27 export class ControllerEspacePerso extends BaseController { 28 data: Data; 29 30 constructor() { 31 super(); 32 this.data = new Data(this); 33 } 34 35 isPersonneMajeur(personne: Personne) { 36 const ageP = age(new Date(), personne.date_naissance); 37 return ageP >= 18; 38 } 39 40 needValidationFicheSanitaire(personne: Personne) { 41 return ( 42 !this.isPersonneMajeur(personne) && 43 !this.isFsUpToDate(personne.id_crypted) 44 ); 45 } 46 47 isFsUpToDate(idPersonneCrypted: string) { 48 let isOk = false; 49 this.data.participants 50 .filter(p => p.id_personne_crypted == idPersonneCrypted) 51 .forEach(p => { 52 isOk = isOk || p.is_fiche_sanitaire_up_to_date; 53 }); 54 return isOk; 55 } 56 57 getCamp(participant: Participant): CampPlus | undefined { 58 return this.data.camps[participant.id_camp]; 59 } 60 61 getPersonneById(idCrypted: string) { 62 return this.data.personnes[idCrypted]; 63 } 64 65 getPersonne(participant: Participant) { 66 return this.getPersonneById(participant.id_personne_crypted); 67 } 68 69 isModificationLocked(part: Participant) { 70 const camp = this.getCamp(part); 71 if (camp == null) return true; 72 const dt = new Date(camp.date_debut); 73 const intervalle = (dt.getTime() - Date.now()) / (1000 * 60 * 60); 74 if (this.data.metas == null) return true; 75 return intervalle < this.data.metas.update_limitation; 76 } 77 78 updateDocumentAide(doc: PublicDocument, aide: Aide) { 79 if (this.data.finances == null || this.data.finances.aides == null) return; 80 const index = this.data.finances.aides.findIndex( 81 a => a.id_crypted == aide.id_crypted 82 ); 83 this.data.finances.aides[index].document = doc; 84 } 85 86 documentsARemplir() { 87 let total = 0; 88 Object.values(this.data.personnes).forEach(personne => { 89 (personne.documents || []).forEach(contrainte => { 90 if ((contrainte.docs || []).length == 0) { 91 total += 1; 92 } 93 }); 94 }); 95 return total; 96 } 97 98 /** Renvoie un nom de page contenant les camps concernés par le dossier */ 99 pageTitle() { 100 const camps = Object.values(this.data.camps) 101 .map(c => c.label) 102 .join(" - "); 103 return "Espace de suivi : " + camps; 104 } 105 106 /** Renvoie `true` si au moins un des séjours demande un acompte. */ 107 get withAcompte() { 108 for (const part of this.data.participants) { 109 const camp = this.getCamp(part); 110 if (camp && camp.schema_paiement == SchemaPaiement.SPAcompte) return true; 111 } 112 return false; 113 } 114 115 /** Renvoie `true` si tous les participants sont en liste d'attente */ 116 get onlyAttente() { 117 for (const part of this.data.participants) { 118 if (part.liste_attente.statut == StatutAttente.Inscrit) return false; 119 } 120 return true; 121 } 122 123 get salutations() { 124 if (this.data.responsable == null) return "Bonjour"; 125 const resp = this.data.responsable; 126 if (resp.prenom == "") { 127 return "Bonjour"; 128 } 129 if (resp.sexe == Sexe.SFemme) { 130 return `Chère ${resp.prenom}`; 131 } 132 return `Chere ${resp.prenom}`; 133 } 134 135 /** renvoie les camps ouverts au sondage */ 136 campsSondages() { 137 const tmp: { [key: number]: CampPlus } = {}; 138 this.data.messages 139 .filter(message => message.kind == MessageKind.MSondage) 140 .map(message => message.contenu as ContenuSondage) 141 .forEach(contenu => { 142 const camp = this.data.camps[contenu.id_camp]; 143 if (camp) { 144 tmp[contenu.id_camp] = camp; 145 } 146 }); 147 return Object.values(tmp).sort((a, b) => a.label.localeCompare(b.label)); 148 } 149 150 isMessageFactureRappel(message: PseudoMessage) { 151 const d = new Date(message.created).valueOf(); 152 const otherFacs = this.data.messages 153 .filter(m => m.kind == MessageKind.MFacture && m.id != message.id) // autre factures 154 .filter(m => new Date(m.created).valueOf() < d); // envoyée avant 155 return otherFacs.length > 0; 156 } 157 158 /** renvoie les informations potentiellement partageable entre 2 participants */ 159 hintsFichesSanitaires(): CompletionFicheSanitaire { 160 const medecinNoms: { [key: string]: boolean } = {}; 161 const medecinTels: { [key: string]: boolean } = {}; 162 const telsAdditionnels: { [key: string]: boolean } = {}; 163 164 Object.values(this.data.personnes).forEach(pers => { 165 if (pers.fiche_sanitaire.medecin.nom) { 166 medecinNoms[pers.fiche_sanitaire.medecin.nom] = true; 167 } 168 if (pers.fiche_sanitaire.medecin.tel) { 169 medecinTels[pers.fiche_sanitaire.medecin.tel] = true; 170 } 171 if (pers.fiche_sanitaire.tel) { 172 telsAdditionnels[pers.fiche_sanitaire.tel] = true; 173 } 174 }); 175 176 return { 177 medecinNoms: Object.keys(medecinNoms), 178 medecinTels: Object.keys(medecinTels), 179 telsAdditionnels: Object.keys(telsAdditionnels) 180 }; 181 } 182 } 183 184 // Singleton responsable des données 185 // et des requêtes serveurs. 186 export const C = new ControllerEspacePerso();