Ajouter garde-fous d utilisation
This commit is contained in:
parent
25470f4642
commit
7352ecef44
9 changed files with 308 additions and 4 deletions
|
|
@ -21,6 +21,8 @@ MODULES_CONSULTATION = [
|
||||||
ModuleTuile(code="C5", nom="Gouvernance", description="Décisions du groupe", icone="📌", couleur="red"),
|
ModuleTuile(code="C5", nom="Gouvernance", description="Décisions du groupe", icone="📌", couleur="red"),
|
||||||
ModuleTuile(code="C7", nom="Mon profil", description="Modifier, PIN, notifications", icone="👤", couleur="gray"),
|
ModuleTuile(code="C7", nom="Mon profil", description="Modifier, PIN, notifications", icone="👤", couleur="gray"),
|
||||||
ModuleTuile(code="C9", nom="Postes à pourvoir", description="Postes disponibles, candidature", icone="🙋", couleur="yellow"),
|
ModuleTuile(code="C9", nom="Postes à pourvoir", description="Postes disponibles, candidature", icone="🙋", couleur="yellow"),
|
||||||
|
ModuleTuile(code="C11", nom="Principes d'utilisation", description="L'application comme outil de service", icone="🧭", couleur="indigo"),
|
||||||
|
ModuleTuile(code="C12", nom="Mode papier", description="Formulaires de reprise en main", icone="🖨️", couleur="gray"),
|
||||||
ModuleTuile(code="S1T", nom="Trésorerie", description="État des résultats, soldes, registre", icone="🏦", couleur="green"),
|
ModuleTuile(code="S1T", nom="Trésorerie", description="État des résultats, soldes, registre", icone="🏦", couleur="green"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
51
docs/GARDE_FOUS_SOCIAUX.md
Normal file
51
docs/GARDE_FOUS_SOCIAUX.md
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# Garde-fous sociaux pour l'application
|
||||||
|
|
||||||
|
Ce document propose des textes de support que le groupe peut lire, adapter et adopter.
|
||||||
|
Ils visent a garder l'application a sa juste place : un outil de service, pas une autorite.
|
||||||
|
|
||||||
|
## Resolution type
|
||||||
|
|
||||||
|
> Le groupe reconnait cette application comme un outil de service. Elle vise a alleger les taches, preserver l'historique et soutenir la transparence. Elle ne remplace pas la conscience de groupe, ne sert pas a surveiller les membres et ne doit jamais etre necessaire pour participer a une reunion. Les membres conservent la possibilite de reprendre les processus sur papier lorsque l'informatique n'est pas disponible.
|
||||||
|
|
||||||
|
## Charte courte d'utilisation
|
||||||
|
|
||||||
|
1. L'application assiste le groupe; elle ne decide pas pour lui.
|
||||||
|
2. Le journal sert a comprendre les changements, corriger les erreurs et proteger l'historique.
|
||||||
|
3. Les permissions suivent les postes de service et doivent etre revues regulierement.
|
||||||
|
4. Les donnees personnelles conservees doivent rester minimales et utiles.
|
||||||
|
5. Les rapports imprimables permettent une reprise en main si l'outil est indisponible.
|
||||||
|
6. Le compte Sysadmin est un outil technique, pas un poste de pouvoir dans le groupe.
|
||||||
|
7. Les decisions importantes demeurent prises en assemblee, selon la conscience de groupe.
|
||||||
|
|
||||||
|
## Message de presentation aux membres
|
||||||
|
|
||||||
|
Cette application a ete concue pour aider les serviteurs du groupe a faire leur service plus simplement.
|
||||||
|
Elle rassemble les informations utiles aux rencontres, assemblees, finances, postes et decisions du groupe.
|
||||||
|
|
||||||
|
Elle ne remplace pas la parole, la confiance, la conscience de groupe ni les traditions.
|
||||||
|
Elle sert surtout a eviter les oublis, faciliter les rapports, garder une trace des changements et permettre une meilleure continuite entre les serviteurs.
|
||||||
|
|
||||||
|
Chaque membre peut consulter ce qui lui est utile selon ses acces.
|
||||||
|
Les actions importantes sont journalisees pour proteger l'historique, non pour surveiller les membres.
|
||||||
|
Lorsque l'informatique n'est pas disponible, le groupe peut continuer sur papier et ressaisir les informations plus tard.
|
||||||
|
|
||||||
|
## Questions a revoir periodiquement
|
||||||
|
|
||||||
|
- Les permissions correspondent-elles encore aux postes reellement occupes?
|
||||||
|
- Les rapports produits aident-ils vraiment les discussions du groupe?
|
||||||
|
- Des donnees inutiles sont-elles conservees?
|
||||||
|
- Le journal est-il utilise pour comprendre et non pour blamer?
|
||||||
|
- Le groupe sait-il continuer une rencontre ou une assemblee sans l'application?
|
||||||
|
- Le mot de passe Sysadmin a-t-il ete change apres installation?
|
||||||
|
- Les sauvegardes sont-elles recentes et protegees?
|
||||||
|
|
||||||
|
## Reprise papier
|
||||||
|
|
||||||
|
Si l'application n'est pas disponible:
|
||||||
|
|
||||||
|
1. Ouvrir le module `Mode papier` si l'app est encore accessible, ou utiliser des formulaires deja imprimes.
|
||||||
|
2. Continuer la rencontre ou l'assemblee normalement.
|
||||||
|
3. Identifier clairement la date, le responsable et les montants.
|
||||||
|
4. Faire approuver les rapports comme d'habitude.
|
||||||
|
5. Ressaisir les donnees dans l'application lorsque le service revient.
|
||||||
|
6. Conserver le papier jusqu'a verification par le secretaire ou le tresorier.
|
||||||
|
|
@ -49,6 +49,8 @@ Le module `Profil` permet de modifier ses informations personnelles :
|
||||||
|
|
||||||
Un membre peut aussi choisir les types de changements pour lesquels il souhaite être notifié, lorsque les notifications sont disponibles sur son appareil.
|
Un membre peut aussi choisir les types de changements pour lesquels il souhaite être notifié, lorsque les notifications sont disponibles sur son appareil.
|
||||||
|
|
||||||
|
Le profil explique aussi quelles données personnelles sont conservées et pourquoi. Il affiche les postes actifs du membre et les modules visibles afin que chacun puisse comprendre d'où viennent ses accès.
|
||||||
|
|
||||||
### Notifications
|
### Notifications
|
||||||
|
|
||||||
Les notifications push sont optionnelles. Le membre choisit les catégories de changements qui l'intéressent depuis son profil. Les notifications dépendent aussi du navigateur, du téléphone et de l'autorisation donnée par l'utilisateur.
|
Les notifications push sont optionnelles. Le membre choisit les catégories de changements qui l'intéressent depuis son profil. Les notifications dépendent aussi du navigateur, du téléphone et de l'autorisation donnée par l'utilisateur.
|
||||||
|
|
@ -66,6 +68,8 @@ La page `Accueil` regroupe ce qu'un membre consulte souvent :
|
||||||
- événements;
|
- événements;
|
||||||
- littérature;
|
- littérature;
|
||||||
- profil;
|
- profil;
|
||||||
|
- principes d'utilisation;
|
||||||
|
- mode papier;
|
||||||
- modules de consultation.
|
- modules de consultation.
|
||||||
|
|
||||||
### Rencontres
|
### Rencontres
|
||||||
|
|
@ -541,6 +545,20 @@ Le rapport d'assemblée d'affaires tient lieu de procès-verbal imprimable. Il r
|
||||||
|
|
||||||
Le rapport de trésorerie présente les résultats du mois précédent et les positions de trésorerie à la fin de ce mois.
|
Le rapport de trésorerie présente les résultats du mois précédent et les positions de trésorerie à la fin de ce mois.
|
||||||
|
|
||||||
|
### Mode papier
|
||||||
|
|
||||||
|
Le module `Mode papier` offre des formulaires vierges imprimables pour :
|
||||||
|
|
||||||
|
- rencontre hebdomadaire;
|
||||||
|
- assemblée d'affaires;
|
||||||
|
- trésorerie.
|
||||||
|
|
||||||
|
Ces formulaires servent de plan de secours. Ils permettent de continuer les activités du groupe si l'application ou le réseau ne sont pas disponibles, puis de ressaisir les données plus tard.
|
||||||
|
|
||||||
|
### Principes d'utilisation
|
||||||
|
|
||||||
|
Le module `Principes d'utilisation` rappelle que l'application est un outil de service. Elle soutient le groupe, mais ne remplace pas la conscience de groupe, la discussion ni les processus papier lorsque nécessaires.
|
||||||
|
|
||||||
## 13. Journal
|
## 13. Journal
|
||||||
|
|
||||||
Le journal conserve les actions modificatrices faites dans l'application.
|
Le journal conserve les actions modificatrices faites dans l'application.
|
||||||
|
|
@ -556,6 +574,8 @@ Le journal présente deux niveaux : l'historique métier, qui explique les chang
|
||||||
|
|
||||||
Les consultations simples ne sont pas journalisées comme actions modificatrices. Le journal est réservé aux exécutifs.
|
Les consultations simples ne sont pas journalisées comme actions modificatrices. Le journal est réservé aux exécutifs.
|
||||||
|
|
||||||
|
Le journal doit servir à comprendre les changements et protéger l'historique, pas à surveiller les membres.
|
||||||
|
|
||||||
## 14. Modifications simultanées
|
## 14. Modifications simultanées
|
||||||
|
|
||||||
Il peut arriver que deux membres exécutifs travaillent sur la même information en même temps.
|
Il peut arriver que deux membres exécutifs travaillent sur la même information en même temps.
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ import ReunionHebdomadaire from './pages/ReunionHebdomadaire';
|
||||||
import AssembleeAffaires from './pages/AssembleeAffaires';
|
import AssembleeAffaires from './pages/AssembleeAffaires';
|
||||||
import AssembleeInvite from './pages/AssembleeInvite';
|
import AssembleeInvite from './pages/AssembleeInvite';
|
||||||
import JournalActions from './pages/JournalActions';
|
import JournalActions from './pages/JournalActions';
|
||||||
|
import PrincipesUtilisation from './pages/PrincipesUtilisation';
|
||||||
|
import ModePapier from './pages/ModePapier';
|
||||||
import BottomNav from './components/BottomNav';
|
import BottomNav from './components/BottomNav';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
|
@ -92,6 +94,8 @@ export default function App() {
|
||||||
case 'M4': pageActive = <EnvoiContributions />; break;
|
case 'M4': pageActive = <EnvoiContributions />; break;
|
||||||
case 'G8': pageActive = <ConfigRepartition />; break;
|
case 'G8': pageActive = <ConfigRepartition />; break;
|
||||||
case 'C9': pageActive = <Impliquer />; break;
|
case 'C9': pageActive = <Impliquer />; break;
|
||||||
|
case 'C11': pageActive = <PrincipesUtilisation />; break;
|
||||||
|
case 'C12': pageActive = <ModePapier />; break;
|
||||||
case 'C10': pageActive = <Tresorerie />; break;
|
case 'C10': pageActive = <Tresorerie />; break;
|
||||||
default: pageActive = <Accueil />;
|
default: pageActive = <Accueil />;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ const COULEURS = {
|
||||||
gray: 'bg-gray-50 border-gray-200 text-gray-700',
|
gray: 'bg-gray-50 border-gray-200 text-gray-700',
|
||||||
};
|
};
|
||||||
|
|
||||||
const NAVIGABLE = ['C7', 'S1', 'S1T', 'S2', 'S3', 'S4', 'S5', 'C1', 'C2', 'C4', 'C5', 'C9', 'G2', 'G9', 'G11', 'G12', 'G13', 'M0', 'M1', 'M2', 'M3', 'M4', 'M5', 'M6'];
|
const NAVIGABLE = ['C7', 'S1', 'S1T', 'S2', 'S3', 'S4', 'S5', 'C1', 'C2', 'C4', 'C5', 'C9', 'C11', 'C12', 'G2', 'G9', 'G11', 'G12', 'G13', 'M0', 'M1', 'M2', 'M3', 'M4', 'M5', 'M6'];
|
||||||
const MODULES_CONTEXTE = new Set(['S0', 'M0', 'M1', 'M2']);
|
const MODULES_CONTEXTE = new Set(['S0', 'M0', 'M1', 'M2']);
|
||||||
|
|
||||||
const CONTEXTES = {
|
const CONTEXTES = {
|
||||||
|
|
@ -22,7 +22,7 @@ const CONTEXTES = {
|
||||||
sections: [
|
sections: [
|
||||||
{ titre: 'À faire maintenant', codes: ['S5', 'C5', 'C9'] },
|
{ titre: 'À faire maintenant', codes: ['S5', 'C5', 'C9'] },
|
||||||
{ titre: 'État', codes: ['S1T', 'C2', 'C1', 'C4'] },
|
{ titre: 'État', codes: ['S1T', 'C2', 'C1', 'C4'] },
|
||||||
{ titre: 'Mon espace', codes: ['C7'] },
|
{ titre: 'Mon espace', codes: ['C7', 'C11', 'C12'] },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
reunion: {
|
reunion: {
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,9 @@ export default function JournalActions() {
|
||||||
</div>
|
</div>
|
||||||
{tab === 'historique' && (
|
{tab === 'historique' && (
|
||||||
<div className="bg-white rounded-2xl p-4 shadow-sm space-y-3">
|
<div className="bg-white rounded-2xl p-4 shadow-sm space-y-3">
|
||||||
|
<p className="text-sm text-gray-600 bg-blue-50 border border-blue-100 rounded-xl p-3">
|
||||||
|
Le journal sert à comprendre les changements et protéger l'historique, pas à surveiller les membres.
|
||||||
|
</p>
|
||||||
<input
|
<input
|
||||||
value={filtres.q}
|
value={filtres.q}
|
||||||
onChange={(e) => updateFiltre('q', e.target.value)}
|
onChange={(e) => updateFiltre('q', e.target.value)}
|
||||||
|
|
@ -210,7 +213,7 @@ export default function JournalActions() {
|
||||||
<div className="grid grid-cols-2 gap-2 text-xs text-gray-500">
|
<div className="grid grid-cols-2 gap-2 text-xs text-gray-500">
|
||||||
<p><span className="font-bold text-gray-600">Domaine</span><br />{domaineLabel(item.table_cible)}</p>
|
<p><span className="font-bold text-gray-600">Domaine</span><br />{domaineLabel(item.table_cible)}</p>
|
||||||
<p><span className="font-bold text-gray-600">Action</span><br />{item.action}</p>
|
<p><span className="font-bold text-gray-600">Action</span><br />{item.action}</p>
|
||||||
<p className="col-span-2 break-all"><span className="font-bold text-gray-600">Objet</span><br />{item.objet_id}</p>
|
<p className="col-span-2 break-all"><span className="font-bold text-gray-600">Référence technique</span><br />{item.objet_id}</p>
|
||||||
{item.chemin_api && <p className="col-span-2 break-all"><span className="font-bold text-gray-600">API</span><br />{item.chemin_api}</p>}
|
{item.chemin_api && <p className="col-span-2 break-all"><span className="font-bold text-gray-600">API</span><br />{item.chemin_api}</p>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
109
frontend/src/pages/ModePapier.jsx
Normal file
109
frontend/src/pages/ModePapier.jsx
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PageHeader from '../components/PageHeader';
|
||||||
|
import { useStore } from '../stores/store';
|
||||||
|
|
||||||
|
const formulaires = [
|
||||||
|
{
|
||||||
|
titre: 'Rencontre hebdomadaire',
|
||||||
|
description: 'Présences informelles, collecte, ventes, jetons et notes de réunion.',
|
||||||
|
fichier: 'rencontre',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
titre: "Assemblée d'affaires",
|
||||||
|
description: 'Ordre du jour, présences, propositions, décisions, postes et rapport du trésorier.',
|
||||||
|
fichier: 'assemblee',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
titre: 'Trésorerie',
|
||||||
|
description: 'Collectes, dépôts, dépenses, réserves et rapprochement mensuel.',
|
||||||
|
fichier: 'tresorerie',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const lignes = (n) => Array.from({ length: n }, (_, i) => `<div class="line">${i + 1}.</div>`).join('');
|
||||||
|
|
||||||
|
function htmlFormulaire(type, groupe) {
|
||||||
|
const nomGroupe = groupe?.nom || 'Groupe';
|
||||||
|
const commun = `
|
||||||
|
<div class="head">
|
||||||
|
<h1>${nomGroupe}</h1>
|
||||||
|
<p>Formulaire papier de reprise en main</p>
|
||||||
|
</div>
|
||||||
|
<div class="meta">
|
||||||
|
<div>Date: ____________________</div>
|
||||||
|
<div>Responsable: ____________________</div>
|
||||||
|
</div>`;
|
||||||
|
const sections = {
|
||||||
|
rencontre: `
|
||||||
|
<h2>Rencontre hebdomadaire</h2>
|
||||||
|
<label>Sujet / thème</label><div class="box"></div>
|
||||||
|
<label>Collecte</label><div class="grid"><div>Montant: __________</div><div>Détenteur: __________</div></div>
|
||||||
|
<label>Ventes littérature / jetons / gâteau</label>${lignes(6)}
|
||||||
|
<label>Remises de jetons / anniversaires</label>${lignes(6)}
|
||||||
|
<label>Notes</label><div class="big"></div>`,
|
||||||
|
assemblee: `
|
||||||
|
<h2>Assemblée d'affaires</h2>
|
||||||
|
<label>Présences</label>${lignes(12)}
|
||||||
|
<label>Rapport du trésorier</label><div class="big"></div>
|
||||||
|
<label>Propositions / décisions</label>${lignes(10)}
|
||||||
|
<label>Postes à pourvoir</label>${lignes(6)}
|
||||||
|
<label>Suites à donner</label><div class="big"></div>`,
|
||||||
|
tresorerie: `
|
||||||
|
<h2>Trésorerie</h2>
|
||||||
|
<label>Encaisse / banque / réserves</label>${lignes(8)}
|
||||||
|
<label>Collectes et ventes reçues</label>${lignes(8)}
|
||||||
|
<label>Dépenses et contributions</label>${lignes(8)}
|
||||||
|
<label>Rapprochement / notes</label><div class="big"></div>`,
|
||||||
|
};
|
||||||
|
return `<!doctype html><html lang="fr"><head><meta charset="utf-8"><title>${nomGroupe} - ${type}</title>
|
||||||
|
<style>
|
||||||
|
@page{size:letter;margin:0.6in} body{font-family:Arial,sans-serif;color:#111;line-height:1.35}
|
||||||
|
.head{border-bottom:2px solid #111;padding-bottom:10px;margin-bottom:14px}.head h1{margin:0;font-size:22px}.head p{margin:4px 0 0;color:#555}
|
||||||
|
h2{font-size:18px;margin:14px 0 10px}.meta{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:16px}
|
||||||
|
label{display:block;font-weight:bold;margin-top:14px}.box{height:42px;border:1px solid #999;margin-top:6px}.big{height:120px;border:1px solid #999;margin-top:6px}
|
||||||
|
.grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;border:1px solid #999;padding:10px;margin-top:6px}
|
||||||
|
.line{height:28px;border-bottom:1px solid #bbb;padding-top:6px}
|
||||||
|
</style></head><body>${commun}${sections[type]}<script>window.print()</script></body></html>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ModePapier() {
|
||||||
|
const { groupe } = useStore();
|
||||||
|
|
||||||
|
const imprimer = (type) => {
|
||||||
|
const win = window.open('', '_blank');
|
||||||
|
if (!win) return;
|
||||||
|
win.document.write(htmlFormulaire(type, groupe));
|
||||||
|
win.document.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-100">
|
||||||
|
<PageHeader titre="Mode papier" sousTitre="Continuer même si l'informatique tombe" />
|
||||||
|
<div className="p-4 space-y-4">
|
||||||
|
<div className="bg-white rounded-2xl p-4 shadow-sm">
|
||||||
|
<p className="text-sm text-gray-700 leading-relaxed">
|
||||||
|
Ces formulaires vierges servent de plan de secours. Ils permettent de poursuivre une rencontre,
|
||||||
|
une assemblée ou une opération de trésorerie, puis de ressaisir les données plus tard.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{formulaires.map((formulaire) => (
|
||||||
|
<button
|
||||||
|
key={formulaire.fichier}
|
||||||
|
type="button"
|
||||||
|
onClick={() => imprimer(formulaire.fichier)}
|
||||||
|
className="w-full bg-white rounded-2xl p-4 shadow-sm text-left active:scale-[0.98] transition"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<span className="text-2xl">🖨️</span>
|
||||||
|
<div className="flex-1">
|
||||||
|
<p className="font-bold text-gray-800">{formulaire.titre}</p>
|
||||||
|
<p className="text-sm text-gray-500 mt-1">{formulaire.description}</p>
|
||||||
|
</div>
|
||||||
|
<span className="text-gray-300">›</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
44
frontend/src/pages/PrincipesUtilisation.jsx
Normal file
44
frontend/src/pages/PrincipesUtilisation.jsx
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PageHeader from '../components/PageHeader';
|
||||||
|
|
||||||
|
const PRINCIPES = [
|
||||||
|
['Outil de service', "L'application soutient les serviteurs; elle ne remplace jamais la conscience de groupe."],
|
||||||
|
['Reprise sur papier', "Les rencontres, assemblées et rapports doivent pouvoir continuer même si l'informatique tombe."],
|
||||||
|
['Sobriété des données', "On conserve seulement les renseignements utiles au fonctionnement du groupe."],
|
||||||
|
['Transparence', "Le journal sert à comprendre les changements et protéger l'historique, pas à surveiller les membres."],
|
||||||
|
['Pouvoirs visibles', "Les accès viennent des postes occupés. Les actions sensibles doivent rester explicables au groupe."],
|
||||||
|
['Participation libre', "L'application ne doit jamais devenir nécessaire pour assister à une réunion ou participer au groupe."],
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function PrincipesUtilisation() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-100">
|
||||||
|
<PageHeader titre="Principes d'utilisation" sousTitre="L'application comme outil de service" />
|
||||||
|
<div className="p-4 space-y-4">
|
||||||
|
<div className="bg-white rounded-2xl p-4 shadow-sm">
|
||||||
|
<p className="text-sm text-gray-700 leading-relaxed">
|
||||||
|
Cette application aide le groupe à alléger les tâches, préserver l'historique et soutenir la transparence.
|
||||||
|
Elle ne gouverne pas le groupe. Les décisions demeurent prises par les membres, selon les pratiques du groupe.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
{PRINCIPES.map(([titre, texte]) => (
|
||||||
|
<div key={titre} className="bg-white rounded-2xl p-4 shadow-sm">
|
||||||
|
<p className="font-bold text-gray-800">{titre}</p>
|
||||||
|
<p className="text-sm text-gray-600 mt-1 leading-relaxed">{texte}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-blue-50 border border-blue-100 rounded-2xl p-4">
|
||||||
|
<p className="font-bold text-aa-blue">Boussole simple</p>
|
||||||
|
<p className="text-sm text-blue-900 mt-1 leading-relaxed">
|
||||||
|
Une fonctionnalité est saine si elle augmente la capacité du groupe à se servir lui-même.
|
||||||
|
Elle devient fragile si elle augmente surtout le contrôle sur les membres.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,15 @@ import {
|
||||||
} from '../utils/pushNotifications';
|
} from '../utils/pushNotifications';
|
||||||
|
|
||||||
export default function Profil() {
|
export default function Profil() {
|
||||||
const { setPage, estSysadmin, logout } = useStore();
|
const {
|
||||||
|
setPage,
|
||||||
|
estSysadmin,
|
||||||
|
logout,
|
||||||
|
postes,
|
||||||
|
modulesConsultation,
|
||||||
|
modulesSaisie,
|
||||||
|
modulesGestion,
|
||||||
|
} = useStore();
|
||||||
const [profil, setProfil] = useState(null);
|
const [profil, setProfil] = useState(null);
|
||||||
const [editing, setEditing] = useState(false);
|
const [editing, setEditing] = useState(false);
|
||||||
const [form, setForm] = useState({});
|
const [form, setForm] = useState({});
|
||||||
|
|
@ -169,6 +177,15 @@ export default function Profil() {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const modulesAccessibles = [
|
||||||
|
...(modulesConsultation || []),
|
||||||
|
...(modulesSaisie || []),
|
||||||
|
...(modulesGestion || []),
|
||||||
|
].reduce((acc, module) => {
|
||||||
|
if (!acc.some((m) => m.code === module.code)) acc.push(module);
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-100">
|
<div className="min-h-screen bg-gray-100">
|
||||||
<div className="bg-aa-blue text-white p-4 flex items-center gap-3">
|
<div className="bg-aa-blue text-white p-4 flex items-center gap-3">
|
||||||
|
|
@ -240,6 +257,51 @@ export default function Profil() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-white rounded-2xl p-4 shadow-sm space-y-3">
|
||||||
|
<div>
|
||||||
|
<h2 className="font-bold text-gray-700">Données conservées</h2>
|
||||||
|
<p className="text-sm text-gray-500 mt-1">
|
||||||
|
L'application conserve seulement les informations utiles au service du groupe.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 gap-2 text-sm">
|
||||||
|
<InfoDonnee nom="Prénom" raison="Identifier les actions et préserver l'historique du groupe." />
|
||||||
|
<InfoDonnee nom="Nom" raison="Faciliter la gestion courante des membres, si renseigné." />
|
||||||
|
<InfoDonnee nom="Courriel ou identifiant" raison="Permettre la connexion et éviter les doublons." />
|
||||||
|
<InfoDonnee nom="Téléphone" raison="Permettre aux serviteurs autorisés de joindre le membre." />
|
||||||
|
<InfoDonnee nom="Date d'abstinence" raison="Afficher les anniversaires de sobriété, si renseignée." />
|
||||||
|
<InfoDonnee nom="Préférences de notification" raison="Respecter les avis que le membre choisit de recevoir." />
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-gray-400">
|
||||||
|
Le droit à l'oubli conserve l'ID et le prénom pour l'historique, puis neutralise les autres renseignements personnels.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-white rounded-2xl p-4 shadow-sm space-y-3">
|
||||||
|
<div>
|
||||||
|
<h2 className="font-bold text-gray-700">Pourquoi ai-je accès à ceci?</h2>
|
||||||
|
<p className="text-sm text-gray-500 mt-1">
|
||||||
|
Les accès viennent des postes actifs occupés. Les modules de consultation sont visibles aux membres connectés.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="bg-gray-50 rounded-xl p-3">
|
||||||
|
<p className="text-xs text-gray-400">Postes actifs</p>
|
||||||
|
<p className="font-medium text-gray-800">{estSysadmin ? 'Sysadmin' : postes?.length ? postes.join(', ') : 'Aucun poste actif'}</p>
|
||||||
|
</div>
|
||||||
|
{modulesAccessibles.length > 0 && (
|
||||||
|
<div className="space-y-1">
|
||||||
|
<p className="text-xs font-bold text-gray-400 uppercase tracking-wide">Modules visibles</p>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{modulesAccessibles.map((module) => (
|
||||||
|
<span key={module.code} className="px-2 py-1 bg-gray-50 rounded-lg text-xs font-medium text-gray-600">
|
||||||
|
{module.nom}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Notifications */}
|
{/* Notifications */}
|
||||||
<div className="bg-white rounded-2xl p-4 shadow-sm space-y-3">
|
<div className="bg-white rounded-2xl p-4 shadow-sm space-y-3">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -356,3 +418,12 @@ export default function Profil() {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function InfoDonnee({ nom, raison }) {
|
||||||
|
return (
|
||||||
|
<div className="bg-gray-50 rounded-xl p-3">
|
||||||
|
<p className="font-bold text-gray-700">{nom}</p>
|
||||||
|
<p className="text-xs text-gray-500 mt-1">{raison}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue