GUYA FIBRE
Suivi interventions FTTH

Saisie d'activité

Enregistrez chaque intervention FTTH réalisée.

Nouvelle intervention
Aujourd'hui
GUYA FIBRE
Connexion

Accédez à votre espace de suivi FTTH

ou

Compte par défaut : admin / guya2024

🤖
`); printWin.document.close(); setTimeout(()=>{ printWin.print(); }, 500); } function resendInvoiceEmail(invoiceId){ const inv = subInvoices.find(i => i.id === invoiceId); if(!inv) return; inv.emailSent = true; inv.emailSentAt = new Date().toISOString(); save(LS_SUB_INVOICES, subInvoices); toast(`📧 Facture ${inv.invoiceNumber} renvoyée à ${inv.userEmail} !`); renderSubscription(); } function renderSubInvoices(){ const session = load(LS_SESSION, null) || JSON.parse(sessionStorage.getItem(LS_SESSION) || 'null'); if(!session) return; const username = session.user; const userInvoices = subInvoices.filter(inv => inv.userId === username); const tbody = document.getElementById('subInvoicesBody'); const emptyEl = document.getElementById('subInvoicesEmpty'); if(userInvoices.length === 0){ tbody.innerHTML = ''; emptyEl.style.display = 'block'; } else { emptyEl.style.display = 'none'; tbody.innerHTML = userInvoices.slice().reverse().map(inv => { const daysLeft = Math.ceil((new Date(inv.retentionExpiry) - new Date()) / (1000*60*60*24)); const retentionBadge = daysLeft > 30 ? `${daysLeft}j` : daysLeft > 7 ? `${daysLeft}j` : `${daysLeft}j`; return ` ${inv.invoiceNumber} ${new Date(inv.createdAt).toLocaleDateString('fr-FR')} ${inv.periodLabel} ${inv.amountTTC.toFixed(2)} € ${inv.emailSent ? '✅ Envoyé' : 'En attente'} ${retentionBadge} `; }).join(''); } } /* ============================================================ SUBSCRIPTION MANAGEMENT (in-app tab) ============================================================ */ function renderSubscription(){ const session = load(LS_SESSION, null) || JSON.parse(sessionStorage.getItem(LS_SESSION) || 'null'); const username = session ? session.user : 'current'; const sub = getActiveSubscription(username); const statusEl = document.getElementById('subStatusContent'); const footEl = document.getElementById('subFootNote'); if(!sub){ statusEl.innerHTML = `
⚠️ Aucun abonnement actif

Vous n'avez pas d'abonnement actif. Choisissez une formule pour continuer à utiliser l'application.

`; if(footEl) footEl.textContent = '⚠️ Pas d\'abonnement'; } else { const planLabel = sub.plan === 'annuel' ? '🏆 Annuel (25 €/mois)' : sub.plan === 'mensuel' ? '📅 Mensuel (30 €/mois)' : '🎁 Essai gratuit'; const endDate = new Date(sub.endDate).toLocaleDateString('fr-FR'); const daysLeft = Math.ceil((new Date(sub.endDate) - new Date()) / (1000*60*60*24)); const statusColor = sub.status === 'trial' ? 'var(--warn)' : 'var(--ok)'; const statusBg = sub.status === 'trial' ? '#F5E7DA' : '#E3EFE4'; const statusLabel = sub.status === 'trial' ? '🎁 Essai gratuit' : '✅ Actif'; statusEl.innerHTML = `
${statusLabel} — ${planLabel}
Fin de période
${endDate}
Jours restants
${daysLeft} jour(s)
${sub.cardLast4 ? `
💳 Carte se terminant par ****${sub.cardLast4}
` : ''} ${sub.status === 'trial' ? `
` : ''} `; if(footEl) footEl.textContent = sub.status === 'trial' ? `🎁 Essai (${daysLeft}j)` : `💎 ${sub.plan === 'annuel' ? 'Annuel' : 'Mensuel'}`; } // Render payment history const userSubs = subscriptions.filter(s => s.userId === username); const tbody = document.getElementById('subHistoryBody'); const emptyEl = document.getElementById('subHistoryEmpty'); if(userSubs.length === 0){ tbody.innerHTML = ''; emptyEl.style.display = 'block'; } else { emptyEl.style.display = 'none'; tbody.innerHTML = userSubs.slice().reverse().map(s => { const planLabel = s.plan === 'annuel' ? 'Annuel' : s.plan === 'mensuel' ? 'Mensuel' : 'Essai gratuit'; const statusBadge = s.status === 'active' ? 'Actif' : s.status === 'trial' ? 'Essai' : 'Expiré'; return ` ${new Date(s.createdAt).toLocaleDateString('fr-FR')} ${planLabel} ${s.priceTotal > 0 ? fmtEUR(s.priceTotal) : 'Gratuit'} ${statusBadge} ${s.cardLast4 ? '****'+s.cardLast4 : '—'} `; }).join(''); } // Render invoices section renderSubInvoices(); } function upgradePlan(plan){ const session = load(LS_SESSION, null) || JSON.parse(sessionStorage.getItem(LS_SESSION) || 'null'); const username = session ? session.user : 'current'; const currentSub = getActiveSubscription(username); if(currentSub && currentSub.plan === plan){ toast(`Vous êtes déjà abonné au plan ${plan}.`); return; } if(confirm(`Voulez-vous passer au plan ${plan === 'annuel' ? 'Annuel (25 €/mois, 300 €/an)' : 'Mensuel (30 €/mois)'} ?`)){ showSubscriptionScreen(username); setTimeout(()=> selectPlan(plan), 300); } } /* ============================================================ INIT ============================================================ */ // Check login - allow direct access without login (Devis & Factures accessible) checkSession(); updateAuthButton(); document.getElementById('f_date').value=new Date().toISOString().slice(0,10); renderPhotoCatGrid(); populateBpuSelect(); renderToday(); renderHistory(); renderBpu(); renderRecap(); renderDocs(); renderRecolement(); renderSubscription(); autoGenerateInvoices(); // Initialize language const savedLang = localStorage.getItem('dtftth_lang') || 'fr'; if(savedLang !== 'fr') { currentLang = savedLang; document.getElementById('langSelector').value = savedLang; document.getElementById('htmlRoot').setAttribute('lang', savedLang); } applyTranslations(); // Update online status for recolement tab window.addEventListener('online', renderRecolement); window.addEventListener('offline', renderRecolement); Now let me add a GDPR/RGPD notice banner at the bottom of the app, before the toast element: /workspace/app/frontend/index.html