Akira-Kurusu commited on
Commit
92f0c1e
·
verified ·
1 Parent(s): deeb3ee

Update web/patients.html

Browse files
Files changed (1) hide show
  1. web/patients.html +100 -18
web/patients.html CHANGED
@@ -186,6 +186,69 @@
186
  margin-bottom: 1rem;
187
  opacity: 0.5;
188
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  </style>
190
  </head>
191
  <body class="vertical light">
@@ -1100,28 +1163,47 @@ function createPatientCard(patient) {
1100
  }
1101
 
1102
  function showAlert(type, message) {
1103
- const alertClass = {
1104
- 'success': 'alert-success',
1105
- 'error': 'alert-danger',
1106
- 'warning': 'alert-warning',
1107
- 'info': 'alert-info'
1108
- }[type] || 'alert-info';
1109
-
1110
- const alertHtml = `
1111
- <div class="alert ${alertClass} alert-dismissible fade show" role="alert">
1112
- ${(function(){var n=type==='error'?'x-circle':type==='success'?'check-circle':type==='warning'?'alert-triangle':'info';return typeof feather!=='undefined'?feather.icons[n].toSvg({'width':16,'height':16,'stroke-width':1.8,'style':'margin-right:6px;vertical-align:middle;'}):'';})()}
1113
- ${message}
1114
- <button type="button" class="close" data-dismiss="alert">
1115
- <span aria-hidden="true">&times;</span>
1116
- </button>
 
 
 
 
 
 
 
 
 
1117
  </div>
 
 
1118
  `;
 
 
 
 
 
 
 
1119
 
1120
- $('.container-fluid').prepend(alertHtml);
 
 
 
1121
 
1122
- setTimeout(() => {
1123
- $('.alert').first().alert('close');
1124
- }, 5000);
1125
  }
1126
 
1127
  function handleLogout() {
 
186
  margin-bottom: 1rem;
187
  opacity: 0.5;
188
  }
189
+
190
+ /* ── TOAST NOTIFICATIONS ─────────────────────────── */
191
+ #toast-container {
192
+ position: fixed;
193
+ bottom: 1.5rem;
194
+ right: 1.5rem;
195
+ z-index: 99999;
196
+ display: flex;
197
+ flex-direction: column;
198
+ gap: 0.6rem;
199
+ pointer-events: none;
200
+ }
201
+ .toast-notify {
202
+ display: flex;
203
+ align-items: flex-start;
204
+ gap: 12px;
205
+ min-width: 300px;
206
+ max-width: 380px;
207
+ padding: 14px 16px;
208
+ border-radius: 10px;
209
+ box-shadow: 0 8px 24px rgba(0,0,0,0.15);
210
+ background: #fff;
211
+ border-left: 5px solid #ccc;
212
+ pointer-events: all;
213
+ opacity: 0;
214
+ transform: translateX(60px);
215
+ transition: opacity 0.3s ease, transform 0.3s ease;
216
+ position: relative;
217
+ overflow: hidden;
218
+ }
219
+ .toast-notify.show { opacity: 1; transform: translateX(0); }
220
+ .toast-notify.hide { opacity: 0; transform: translateX(60px); }
221
+ .toast-notify.toast-success { border-left-color: #28a745; }
222
+ .toast-notify.toast-error { border-left-color: #dc3545; }
223
+ .toast-notify.toast-warning { border-left-color: #ffc107; }
224
+ .toast-notify.toast-info { border-left-color: #17a2b8; }
225
+ .toast-icon { flex-shrink: 0; margin-top: 1px; }
226
+ .toast-success .toast-icon svg { stroke: #28a745; }
227
+ .toast-error .toast-icon svg { stroke: #dc3545; }
228
+ .toast-warning .toast-icon svg { stroke: #ffc107; }
229
+ .toast-info .toast-icon svg { stroke: #17a2b8; }
230
+ .toast-body { flex: 1; }
231
+ .toast-title { font-weight: 600; font-size: 0.875rem; margin-bottom: 2px; }
232
+ .toast-success .toast-title { color: #155724; }
233
+ .toast-error .toast-title { color: #721c24; }
234
+ .toast-warning .toast-title { color: #856404; }
235
+ .toast-info .toast-title { color: #0c5460; }
236
+ .toast-msg { font-size: 0.825rem; color: #555; line-height: 1.4; }
237
+ .toast-close {
238
+ background: none; border: none; font-size: 1rem;
239
+ line-height: 1; color: #aaa; cursor: pointer; padding: 0; flex-shrink: 0;
240
+ }
241
+ .toast-close:hover { color: #333; }
242
+ .toast-progress {
243
+ position: absolute;
244
+ bottom: 0; left: 0;
245
+ height: 3px;
246
+ border-radius: 0 0 0 10px;
247
+ }
248
+ .toast-success .toast-progress { background: #28a745; }
249
+ .toast-error .toast-progress { background: #dc3545; }
250
+ .toast-warning .toast-progress { background: #ffc107; }
251
+ .toast-info .toast-progress { background: #17a2b8; }
252
  </style>
253
  </head>
254
  <body class="vertical light">
 
1163
  }
1164
 
1165
  function showAlert(type, message) {
1166
+ if (!document.getElementById('toast-container')) {
1167
+ const container = document.createElement('div');
1168
+ container.id = 'toast-container';
1169
+ document.body.appendChild(container);
1170
+ }
1171
+ const container = document.getElementById('toast-container');
1172
+
1173
+ const icons = {
1174
+ success: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>',
1175
+ error: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>',
1176
+ warning: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
1177
+ info: '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>'
1178
+ };
1179
+ const titles = { success: 'Éxito', error: 'Error', warning: 'Advertencia', info: 'Información' };
1180
+ const duration = type === 'error' ? 6000 : 4000;
1181
+
1182
+ const toast = document.createElement('div');
1183
+ toast.className = `toast-notify toast-${type}`;
1184
+ toast.innerHTML = `
1185
+ <div class="toast-icon">${icons[type] || icons.info}</div>
1186
+ <div class="toast-body">
1187
+ <div class="toast-title">${titles[type] || 'Aviso'}</div>
1188
+ <div class="toast-msg">${message}</div>
1189
  </div>
1190
+ <button class="toast-close" onclick="this.closest('.toast-notify').remove()">&times;</button>
1191
+ <div class="toast-progress" style="width:100%;transition:width ${duration}ms linear;"></div>
1192
  `;
1193
+ container.appendChild(toast);
1194
+
1195
+ requestAnimationFrame(() => requestAnimationFrame(() => {
1196
+ toast.classList.add('show');
1197
+ const bar = toast.querySelector('.toast-progress');
1198
+ if (bar) requestAnimationFrame(() => { bar.style.width = '0%'; });
1199
+ }));
1200
 
1201
+ const timer = setTimeout(() => {
1202
+ toast.classList.add('hide');
1203
+ toast.addEventListener('transitionend', () => toast.remove(), { once: true });
1204
+ }, duration);
1205
 
1206
+ toast.querySelector('.toast-close').addEventListener('click', () => clearTimeout(timer));
 
 
1207
  }
1208
 
1209
  function handleLogout() {