inrplus / index.html
willynabole's picture
Génére une application mobile et web minimaliste pour la *télésurveillance des patients sous traitement anticoagulant* dénommé "INR+", avec : --- ### 🔷 **Technologies** * **Frontend** : React JS (version récente), React Router pour la navigation. * **Backend** : Java avec **Spring Boot**, REST API sécurisée. * **Base de données** : MySQL (Schéma relationnel simple). * **Sécurité** : Authentification avec JWT, rôle Patient ou Médecin. * **Style** : CSS moderne ou Tailwind pour UI simple et responsive. --- ### 🔷 **Interface d’accueil (Splash screen)** Créer une **page d’accueil initiale** avec les éléments suivants : * Logo **Patient** en bas à gauche * Logo **Médecin** en haut à droite * Logo de l’application **au centre** * Lorsqu’un logo est cliqué, rediriger vers l’écran **Connexion / Inscription**, avec sélection de rôle (`"patient"` ou `"medecin"`). --- ### 🔷 **Écrans pour le Médecin** | Fonction | | ---------------------------------- | --------------------------------------------------- | | Vue synthétique des patients suivis, alertes, stats | | Liste des patients, ajout/modification de dossiers | | Visualisation graphique de l’historique INR | | Ajout/modification d’une dose AVK | | Génération de bulletin d’analyse INR | | Vue des statistiques par patient | | Alertes critiques patients, rappels à traiter | --- ### 🔷 **Écrans pour le Patient** | Fonction | | ----------------------- | ---------------------------------------------- | | Dernière valeur INR, prochaine dose, rappels | | Formulaire d’enregistrement INR ou upload CSV | | Liste des médicaments, rappels | | Signalement (saignements, douleurs) | | Liste des rendez-vous, ajout/modif | | Alertes INR anormaux, oublis, messages système | --- ### 🔷 **Backend - API nécessaires (Spring Boot)** Créer des contrôleurs REST avec endpoints pour : * Authentification (inscription / login / JWT / rôles) * Gestion des utilisateurs * INR : Création, consultation, historique * Médicaments : prescription / rappel * Symptômes : enregistrement * Notifications : envoi / consultation * Statistiques : calcul INR moyens, alertes * Dossiers patients : CRUD * Rendez-vous : création / modification --- ### 🔷 **Base de Données MySQL – --- Génère le **squelette complet de l’application**, avec tous les dossiers et composants nécessaires, ainsi que le backend prêt à être lancé avec Spring Boot (incluant `application.properties` pour la config MySQL, Swagger, sécurité). --- Souhaites-tu aussi que je te fournisse maintenant les **diagrammes UML (cas d’utilisation, séquence, classes)** ou le **squelette de code généré avec ce prompt** ? - Follow Up Deployment
9feaeef verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>INR+ - Télésurveillance Anticoagulant</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
<style>
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.fade-in {
animation: fadeIn 0.6s ease-out;
}
.logo-hover {
transition: all 0.3s ease;
}
.logo-hover:hover {
transform: scale(1.1);
filter: drop-shadow(0 4px 20px rgba(59, 130, 246, 0.5));
}
.role-card {
backdrop-filter: blur(10px);
transition: all 0.3s ease;
}
.role-card:hover {
transform: translateY(-5px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body class="bg-gradient-to-br from-blue-50 to-indigo-100 min-h-screen">
<!-- Splash Screen -->
<div id="splashScreen" class="min-h-screen flex items-center justify-center relative overflow-hidden">
<!-- Background Pattern -->
<div class="absolute inset-0 opacity-10">
<div class="absolute top-10 left-10 w-32 h-32 bg-blue-500 rounded-full"></div>
<div class="absolute bottom-20 right-20 w-48 h-48 bg-indigo-500 rounded-full"></div>
<div class="absolute top-1/2 left-1/3 w-24 h-24 bg-purple-500 rounded-full"></div>
</div>
<!-- Main Logo -->
<div class="text-center z-10">
<div class="logo-hover cursor-pointer inline-block">
<div class="w-32 h-32 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-full flex items-center justify-center mb-4 shadow-2xl">
<i data-lucide="heart-pulse" class="w-16 h-16 text-white"></i>
</div>
<h1 class="text-4xl font-bold text-gray-800 mb-2">INR+</h1>
<p class="text-gray-600">Télésurveillance des patients sous anticoagulant</p>
</div>
</div>
<!-- Role Selection -->
<div class="absolute bottom-8 left-8">
<button onclick="selectRole('patient')" class="role-card bg-white/80 p-6 rounded-2xl shadow-lg cursor-pointer">
<div class="text-center">
<div class="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-3">
<i data-lucide="user" class="w-8 h-8 text-green-600"></i>
</div>
<h3 class="font-semibold text-gray-800">Patient</h3>
<p class="text-sm text-gray-600 mt-1">Accéder à mes données</p>
</div>
</button>
</div>
<div class="absolute top-8 right-8">
<button onclick="selectRole('medecin')" class="role-card bg-white/80 p-6 rounded-2xl shadow-lg cursor-pointer">
<div class="text-center">
<div class="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-3">
<i data-lucide="stethoscope" class="w-8 h-8 text-red-600"></i>
</div>
<h3 class="font-semibold text-gray-800">Médecin</h3>
<p class="text-sm text-gray-600 mt-1">Gérer mes patients</p>
</div>
</button>
</div>
</div>
<!-- Auth Screen -->
<div id="authScreen" class="hidden min-h-screen flex items-center justify-center p-4">
<div class="max-w-md w-full">
<div class="bg-white rounded-2xl shadow-xl p-8 fade-in">
<div class="text-center mb-8">
<div class="w-20 h-20 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-full flex items-center justify-center mx-auto mb-4">
<i data-lucide="heart-pulse" class="w-10 h-10 text-white"></i>
</div>
<h2 class="text-2xl font-bold text-gray-800">INR+</h2>
<p class="text-gray-600 mt-2" id="authSubtitle">Connexion</p>
</div>
<!-- Toggle Auth Mode -->
<div class="flex mb-6 bg-gray-100 rounded-lg p-1">
<button id="loginBtn" onclick="toggleAuthMode('login')"
class="flex-1 py-2 rounded-md text-sm font-medium transition">
Connexion
</button>
<button id="registerBtn" onclick="toggleAuthMode('register')"
class="flex-1 py-2 rounded-md text-sm font-medium transition">
Inscription
</button>
</div>
<!-- Forms -->
<form id="loginForm" class="space-y-4">
<input type="hidden" id="role" name="role" value="">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input type="email" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Mot de passe</label>
<input type="password" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
</div>
<button type="submit" class="w-full bg-gradient-to-r from-blue-500 to-indigo-600 text-white py-2 rounded-lg font-medium hover:from-blue-600 hover:to-indigo-700 transition">
Se connecter
</button>
</form>
<form id="registerForm" class="hidden space-y-4">
<input type="hidden" id="regRole" name="role" value="">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Nom</label>
<input type="text" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input type="email" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Mot de passe</label>
<input type="password" required minlength="6" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500">
</div>
<div id="medecinFields" class="hidden space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Numéro RPPS</label>
<input type="text" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Spécialité</label>
<select class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500">
<option>Cardiologie</option>
<option>Hématologie</option>
<option>Médecine générale</option>
</select>
</div>
</div>
<button type="submit" class="w-full bg-gradient-to-r from-green-500 to-emerald-600 text-white py-2 rounded-lg font-medium hover:from-green-600 hover:to-emerald-700 transition">
S'inscrire
</button>
</form>
</div>
</div>
</div>
<!-- Patient Dashboard -->
<div id="patientDashboard" class="hidden min-h-screen bg-gray-50">
<!-- Header -->
<header class="bg-white shadow-sm border-b">
<div class="max-w-7xl mx-auto px-4 py-4 flex items-center justify-between">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-lg flex items-center justify-center">
<i data-lucide="heart-pulse" class="w-6 h-6 text-white"></i>
</div>
<h1 class="text-xl font-bold text-gray-800">INR+ Patient</h1>
</div>
<button onclick="logout()" class="text-gray-600 hover:text-gray-800">
<i data-lucide="log-out" class="w-6 h-6"></i>
</button>
</div>
</header>
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 py-8">
<!-- Quick Stats -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-xl shadow-sm p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-600">Dernière INR</p>
<p class="text-2xl font-bold text-gray-800">2.5</p>
</div>
<div class="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center">
<i data-lucide="activity" class="w-6 h-6 text-green-600"></i>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-600">Prochaine dose</p>
<p class="text-2xl font-bold text-gray-800">5mg</p>
</div>
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center">
<i data-lucide="pill" class="w-6 h-6 text-blue-600"></i>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-600">Prochain RDV</p>
<p class="text-2xl font-bold text-gray-800">15/12</p>
</div>
<div class="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center">
<i data-lucide="calendar" class="w-6 h-6 text-purple-600"></i>
</div>
</div>
</div>
</div>
<!-- Actions -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="bg-white rounded-xl shadow-sm p-6">
<h3 class="text-lg font-semibold text-gray-800 mb-4">Actions rapides</h3>
<div class="space-y-3">
<button onclick="showModal('inrModal')" class="w-full text-left px-4 py-3 bg-blue-50 rounded-lg hover:bg-blue-100 transition flex items-center space-x-3">
<i data-lucide="plus" class="w-5 h-5 text-blue-600"></i>
<span class="text-gray-700">Enregistrer une nouvelle INR</span>
</button>
<button onclick="showModal('symptomModal')" class="w-full text-left px-4 py-3 bg-red-50 rounded-lg hover:bg-red-100 transition flex items-center space-x-3">
<i data-lucide="alert-triangle" class="w-5 h-5 text-red-600"></i>
<span class="text-gray-700">Signaler des symptômes</span>
</button>
<button onclick="showModal('appointmentModal')" class="w-full text-left px-4 py-3 bg-purple-50 rounded-lg hover:bg-purple-100 transition flex items-center space-x-3">
<i data-lucide="calendar-plus" class="w-5 h-5 text-purple-600"></i>
<span class="text-gray-700">Prendre rendez-vous</span>
</button>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm p-6">
<h3 class="text-lg font-semibold text-gray-800 mb-4">Médicaments</h3>
<div class="space-y-3">
<div class="flex items-center justify-between">
<div>
<p class="font-medium text-gray-800">Warfarin 5mg</p>
<p class="text-sm text-gray-600">1 comprimé / jour</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" checked class="sr-only peer">
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-green-600"></div>
</label>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- Médecin Dashboard -->
<div id="medecinDashboard" class="hidden min-h-screen bg-gray-50">
<!-- Header -->
<header class="bg-white shadow-sm border-b">
<div class="max-w-7xl mx-auto px-4 py-4 flex items-center justify-between">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-lg flex items-center justify-center">
<i data-lucide="heart-pulse" class="w-6 h-6 text-white"></i>
</div>
<h1 class="text-xl font-bold text-gray-800">INR+ Médecin</h1>
</div>
<button onclick="logout()" class="text-gray-600 hover:text-gray-800">
<i data-lucide="log-out" class="w-6 h-6"></i>
</button>
</div>
</header>
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 py-8">
<!-- Stats -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
<div class="bg-white rounded-xl shadow-sm p-6">
<p class="text-sm text-gray-600">Patients actifs</p>
<p class="text-2xl font-bold text-gray-800">24</p>
</div>
<div class="bg-white rounded-xl shadow-sm p-6">
<p class="text-sm text-gray-600">Alertes en attente</p>
<p class="text-2xl font-bold text-red-600">3</p>
</div>
<div class="bg-white rounded-xl shadow-sm p-6">
<p class="text-sm text-gray-600">Contrôles cette semaine</p>
<p class="text-2xl font-bold text-gray-800">12</p>
</div>
<div class="bg-white rounded-xl shadow-sm p-6">
<p class="text-sm text-gray-600">RDV à venir</p>
<p class="text-2xl font-bold text-gray-800">8</p>
</div>
</div>
<!-- Patient List -->
<div class="bg-white rounded-xl shadow-sm">
<div class="p-6 border-b">
<h3 class="text-lg font-semibold text-gray-800">Mes patients</h3>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Patient</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Dernière INR</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Date</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Statut</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tr>
<td class="px-6 py-4">
<div>
<p class="font-medium text-gray-800">Jean Dupont</p>
<p class="text-sm text-gray-600">jean.dupont@email.com</p>
</div>
</td>
<td class="px-6 py-4">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
2.5
</span>
</td>
<td class="px-6 py-4 text-sm text-gray-600">Aujourd'hui</td>
<td class="px-6 py-4">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
Stable
</span>
</td>
<td class="px-6 py-4">
<button class="text-blue-600 hover:text-blue-800">
<i data-lucide="eye" class="w-4 h-4"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</main>
</div>
<!-- Modals -->
<div id="inrModal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
<div class="bg-white rounded-xl max-w-md w-full p-6">
<h3 class="text-lg font-semibold text-gray-800 mb-4">Enregistrer une INR</h3>
<form class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Valeur INR</label>
<input type="number" step="0.1" required class="w-full px-4 py-2 border border-gray-300 rounded-lg">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Date</label>
<input type="date" required class="w-full px-4 py-2 border border-gray-300 rounded-lg">
</div>
<div class="flex space-x-3">
<button type="button" onclick="hideModal('inrModal')" class="flex-1 px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50">Annuler</button>
<button type="submit" class="flex-1 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">Enregistrer</button>
</div>
</form>
</div>
</div>
<script>
// Initialize Lucide icons
lucide.createIcons();
// Global state
let currentRole = null;
// Navigation functions
function selectRole(role) {
currentRole = role;
document.getElementById('splashScreen').classList.add('hidden');
document.getElementById('authScreen').classList.remove('hidden');
document.getElementById('role').value = role;
document.getElementById('regRole').value = role;
if (role === 'medecin') {
document.getElementById('medecinFields').classList.remove('hidden');
document.getElementById('authSubtitle').textContent = 'Connexion Médecin';
} else {
document.getElementById('authSubtitle').textContent = 'Connexion Patient';
}
}
function toggleAuthMode(mode) {
const loginBtn = document.getElementById('loginBtn');
const registerBtn = document.getElementById('registerBtn');
const loginForm = document.getElementById('loginForm');
const registerForm = document.getElementById('registerForm');
if (mode === 'login') {
loginBtn.className = 'flex-1 py-2 rounded-md text-sm font-medium bg-white shadow-sm';
registerBtn.className = 'flex-1 py-2 rounded-md text-sm font-medium text-gray-500';
loginForm.classList.remove('hidden');
registerForm.classList.add('hidden');
} else {
loginBtn.className = 'flex-1 py-2 rounded-md text-sm font-medium text-gray-500';
registerBtn.className = 'flex-1 py-2 rounded-md text-sm font-medium bg-white shadow-sm';
loginForm.classList.add('hidden');
registerForm.classList.remove('hidden');
}
}
// Form submissions
document.getElementById('loginForm').addEventListener('submit', (e) => {
e.preventDefault();
if (currentRole === 'patient') {
document.getElementById('authScreen').classList.add('hidden');
document.getElementById('patientDashboard').classList.remove('hidden');
} else {
document.getElementById('authScreen').classList.add('hidden');
document.getElementById('medecinDashboard').classList.remove('hidden');
}
});
document.getElementById('registerForm').addEventListener('submit', (e) => {
e.preventDefault();
if (currentRole === 'patient') {
document.getElementById('authScreen').classList.add('hidden');
document.getElementById('patientDashboard').classList.remove('hidden');
} else {
document.getElementById('authScreen').classList.add('hidden');
document.getElementById('medecinDashboard').classList.remove('hidden');
}
});
// Modal functions
function showModal(modalId) {
document.getElementById(modalId).classList.remove('hidden');
}
function hideModal(modalId) {
document.getElementById(modalId).classList.add('hidden');
}
// Logout
function logout() {
document.getElementById('patientDashboard').classList.add('hidden');
document.getElementById('medecinDashboard').classList.add('hidden');
document.getElementById('splashScreen').classList.remove('hidden');
currentRole = null;
}
// Close modals on outside click
window.addEventListener('click', (e) => {
if (e.target.classList.contains('fixed') && e.target.classList.contains('bg-opacity-50')) {
e.target.classList.add('hidden');
}
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=willynabole/inrplus" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>