From ea06d4c98201cbb4781375dbc119f9aa241c7f0b Mon Sep 17 00:00:00 2001 From: odentas Date: Wed, 22 Oct 2025 10:55:20 +0200 Subject: [PATCH] WIP: modifs sur Mac Mini --- app/(app)/simulateur/page.tsx | 12 --- .../contrats/[id]/employee-email/route.ts | 101 ++++++++++++++++++ components/LogoutButton.tsx | 1 - components/MaintenanceButton.tsx | 4 - components/PostHogIdentifier.tsx | 5 +- components/PostHogProvider.tsx | 15 +-- components/contrats/NouveauCDDUForm.tsx | 1 - components/simulateur/SimulateurContent.tsx | 12 --- components/staff/ContractsGrid.tsx | 88 ++++++++++++--- public/simulateur-embed.html | 2 - 10 files changed, 179 insertions(+), 62 deletions(-) create mode 100644 app/api/staff/contrats/[id]/employee-email/route.ts diff --git a/app/(app)/simulateur/page.tsx b/app/(app)/simulateur/page.tsx index 7c84274..d8fdf7c 100644 --- a/app/(app)/simulateur/page.tsx +++ b/app/(app)/simulateur/page.tsx @@ -45,18 +45,6 @@ export default function SimulateurPage() { plafond_urssaf: data.plafond_urssaf, timestamp: data.timestamp }); - - console.log('📊 PostHog: Événement simulateur_calculation enrichi envoyé', { - categorie: data.categorie, - ccn: data.ccn_nom, - type_calcul: data.type_calcul, - montant_saisi: data.montant_saisi, - resultats: { - brut: data.resultat_brut, - net: data.resultat_net, - cost: data.resultat_cost - } - }); } }; diff --git a/app/api/staff/contrats/[id]/employee-email/route.ts b/app/api/staff/contrats/[id]/employee-email/route.ts new file mode 100644 index 0000000..1373ff1 --- /dev/null +++ b/app/api/staff/contrats/[id]/employee-email/route.ts @@ -0,0 +1,101 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'; +import { cookies } from 'next/headers'; + +// GET /api/staff/contrats/[id]/employee-email +// Récupère l'email du salarié pour un contrat +export async function GET( + req: NextRequest, + { params }: { params: { id: string } } +) { + try { + const contractId = params.id; + + if (!contractId) { + return NextResponse.json({ error: 'Contract ID manquant' }, { status: 400 }); + } + + // Vérification de l'authentification + const sb = createRouteHandlerClient({ cookies }); + const { data: { user } } = await sb.auth.getUser(); + if (!user) { + return NextResponse.json({ error: 'Non autorisé' }, { status: 401 }); + } + + // Vérifier staff pour lire la cible via cookie active_org_id + let isStaff = false; + try { + const { data } = await sb.from('staff_users').select('is_staff').eq('user_id', user.id).maybeSingle(); + isStaff = !!data?.is_staff; + } catch {} + + let orgId: string | null = null; + try { + if (isStaff) { + const c = cookies(); + orgId = c.get('active_org_id')?.value || null; + } else { + const { data, error } = await sb + .from('organization_members') + .select('org_id') + .eq('user_id', user.id) + .single(); + if (error || !data?.org_id) { + return NextResponse.json({ error: 'Aucune organisation active' }, { status: 403 }); + } + orgId = data.org_id; + } + } catch {} + + // Récupération des données du contrat depuis Supabase (cddu_contracts) + let query = sb + .from('cddu_contracts') + .select(` + id, + employee_matricule, + org_id + `) + .eq('id', contractId); + + if (orgId) { + query = query.eq('org_id', orgId); + } + + const { data: contract, error: contractError } = await query.single(); + + if (contractError || !contract) { + console.error('Erreur récupération contrat:', contractError); + return NextResponse.json({ error: 'Contrat non trouvé' }, { status: 404 }); + } + + // Récupérer l'email du salarié depuis salaries.adresse_mail + let employee_email: string | null = null; + if (contract.employee_matricule) { + try { + let salQ = sb + .from('salaries') + .select('adresse_mail') + .or(`code_salarie.eq.${contract.employee_matricule},num_salarie.eq.${contract.employee_matricule}`) + .limit(1); + if (orgId) salQ = salQ.eq('employer_id', orgId); + const { data: salData, error: salErr } = await salQ; + if (!salErr && salData && salData[0]?.adresse_mail) { + employee_email = salData[0].adresse_mail as string; + } + } catch (e) { + console.warn('Impossible de récupérer adresse_mail depuis salaries:', e); + } + } + + return NextResponse.json({ + employee_email: employee_email || null + }); + + } catch (error: any) { + console.error('Erreur:', error); + return NextResponse.json({ + error: 'Erreur lors de la récupération de l\'email', + message: error.message + }, { status: 500 }); + } +} diff --git a/components/LogoutButton.tsx b/components/LogoutButton.tsx index 1636a81..8a2716f 100644 --- a/components/LogoutButton.tsx +++ b/components/LogoutButton.tsx @@ -29,7 +29,6 @@ export default function LogoutButton({ variant = "default", className }: { varia // 2. Réinitialiser l'identité PostHog posthog?.reset(); - console.log('👋 PostHog: Utilisateur déconnecté'); // 3. Nettoyage complet côté client (au cas où il resterait des données) try { diff --git a/components/MaintenanceButton.tsx b/components/MaintenanceButton.tsx index 5fc12dc..89e134d 100644 --- a/components/MaintenanceButton.tsx +++ b/components/MaintenanceButton.tsx @@ -39,7 +39,6 @@ export function MaintenanceButton({ isStaff }: MaintenanceButtonProps) { const data = await response.json(); setStatus(data); } else { - console.warn("API maintenance not available yet, using default status"); // Fallback par défaut si l'API n'existe pas encore setStatus({ is_maintenance_mode: false, @@ -139,9 +138,6 @@ export function MaintenanceButton({ isStaff }: MaintenanceButtonProps) { } }; - // Debug: afficher les valeurs pour déboguer - console.log('MaintenanceButton Debug:', { isStaff, status }); - // Ne pas afficher le composant si ce n'est pas un staff if (!isStaff) { return null; diff --git a/components/PostHogIdentifier.tsx b/components/PostHogIdentifier.tsx index 41ef580..7339d96 100644 --- a/components/PostHogIdentifier.tsx +++ b/components/PostHogIdentifier.tsx @@ -34,13 +34,10 @@ export default function PostHogIdentifier() { company_name: me.active_org_name, company_id: me.active_org_id, is_staff: me.is_staff || false, - // Ajoutez d'autres propriétés utiles pour vos analytics }); - - console.log('👤 PostHog: Utilisateur identifié:', me.user?.email || me.email, 'ID:', userId); } } catch (e) { - console.error('❌ PostHog: Erreur lors de l\'identification:', e); + console.error('PostHog: Erreur lors de l\'identification:', e); } })(); }, [posthog]); diff --git a/components/PostHogProvider.tsx b/components/PostHogProvider.tsx index 05838f2..94417ca 100644 --- a/components/PostHogProvider.tsx +++ b/components/PostHogProvider.tsx @@ -11,28 +11,19 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) { const key = process.env.NEXT_PUBLIC_POSTHOG_KEY; const host = process.env.NEXT_PUBLIC_POSTHOG_HOST; - // Debug: vérifier que les variables d'environnement sont bien chargées - console.log('🔍 PostHog - Initialisation...'); - console.log('🔑 Key:', key ? `${key.substring(0, 10)}...` : '❌ MANQUANTE'); - console.log('🌐 Host:', host || '❌ MANQUANT'); - if (!key || !host) { - console.error('❌ PostHog: Variables d\'environnement manquantes. Avez-vous redémarré le serveur après avoir ajouté NEXT_PUBLIC_POSTHOG_KEY et NEXT_PUBLIC_POSTHOG_HOST ?'); + console.error('PostHog: Variables d\'environnement manquantes'); return; } posthog.init(key, { api_host: host, person_profiles: 'identified_only', - capture_pageview: false, // On gère les pageviews manuellement avec PostHogPageView + capture_pageview: false, capture_pageleave: true, loaded: (posthog) => { - console.log('✅ PostHog initialisé avec succès!'); - // Rendre posthog accessible globalement pour les tests en dev if (process.env.NODE_ENV === 'development') { - posthog.debug(true); // Active les logs en dev - (window as any).posthog = posthog; // Exposer pour les tests console - console.log('💡 Vous pouvez maintenant utiliser "window.posthog" dans la console'); + (window as any).posthog = posthog; } }, }); diff --git a/components/contrats/NouveauCDDUForm.tsx b/components/contrats/NouveauCDDUForm.tsx index 8ec0a50..19c3ba1 100644 --- a/components/contrats/NouveauCDDUForm.tsx +++ b/components/contrats/NouveauCDDUForm.tsx @@ -1352,7 +1352,6 @@ useEffect(() => { has_notes: !!payload.notes, validation_immediate: payload.valider_direct, }); - console.log('📊 PostHog: Événement contract_created envoyé'); } // Autoriser la navigation après soumission + feedback diff --git a/components/simulateur/SimulateurContent.tsx b/components/simulateur/SimulateurContent.tsx index 8a0907a..e04005d 100644 --- a/components/simulateur/SimulateurContent.tsx +++ b/components/simulateur/SimulateurContent.tsx @@ -50,18 +50,6 @@ export default function SimulateurContent({ hideInfoPanel = false }: SimulateurC // Ajout du contexte sidebar opened_from: 'sidebar' }); - - console.log('📊 PostHog: Événement simulateur_calculation (sidebar) enrichi envoyé', { - categorie: data.categorie, - ccn: data.ccn_nom, - type_calcul: data.type_calcul, - montant_saisi: data.montant_saisi, - resultats: { - brut: data.resultat_brut, - net: data.resultat_net, - cost: data.resultat_cost - } - }); } }; diff --git a/components/staff/ContractsGrid.tsx b/components/staff/ContractsGrid.tsx index 3297d0a..7d4eb8f 100644 --- a/components/staff/ContractsGrid.tsx +++ b/components/staff/ContractsGrid.tsx @@ -3,7 +3,7 @@ import { useEffect, useMemo, useState, useRef, useImperativeHandle, forwardRef } from "react"; import { supabase } from "@/lib/supabaseClient"; import Link from "next/link"; -import { RefreshCw, Check, X, Settings, FileText, CheckCircle, BarChart3, Eye, ChevronDown, Trash2, FileDown, FileSignature, DollarSign, XCircle, BellRing } from "lucide-react"; +import { RefreshCw, Check, X, Settings, FileText, CheckCircle, BarChart3, Eye, ChevronDown, Trash2, FileDown, FileSignature, Euro, XCircle, BellRing } from "lucide-react"; import { toast } from "sonner"; import BulkPdfProgressModal from "./BulkPdfProgressModal"; import PdfVerificationModal from "./PdfVerificationModal"; @@ -1130,8 +1130,23 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract }, []); // Fonction pour relancer un salarié spécifique - const handleReminderClick = (contract: any) => { + const handleReminderClick = async (contract: any) => { setSelectedContractForReminder(contract); + + // Récupérer l'email du salarié depuis la base de données + try { + const response = await fetch(`/api/staff/contrats/${contract.id}/employee-email`); + if (response.ok) { + const result = await response.json(); + setSelectedContractForReminder({ + ...contract, + employee_email: result.employee_email + }); + } + } catch (error) { + console.error('Erreur récupération email:', error); + } + setShowEmployeeReminderModal(true); }; @@ -1167,6 +1182,50 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract } }; + // Fonction pour relancer en masse tous les salariés sélectionnés + const handleBulkReminderClick = async () => { + if (selectedContractIds.size === 0) { + toast.error("Aucun contrat sélectionné"); + return; + } + + setIsLoadingReminder(true); + const contractIds = Array.from(selectedContractIds); + let successCount = 0; + let errorCount = 0; + + try { + for (const contractId of contractIds) { + try { + const response = await fetch('/api/staff/contrats/relance-salarie', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ contractId }), + }); + + if (response.ok) { + successCount++; + } else { + errorCount++; + } + } catch (error) { + errorCount++; + } + } + + if (successCount > 0) { + toast.success(`${successCount} email${successCount > 1 ? 's' : ''} de relance envoyé${successCount > 1 ? 's' : ''} avec succès`); + } + if (errorCount > 0) { + toast.error(`${errorCount} erreur${errorCount > 1 ? 's' : ''} lors de l'envoi`); + } + } finally { + setIsLoadingReminder(false); + } + }; + // derive options from initialData for simple selects const structures = useMemo(() => { const uniqueStructures = Array.from(new Set((initialData || []).map((r) => r.structure).filter(Boolean) as string[])); @@ -1514,6 +1573,18 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract {isGeneratingESign ? "Envoi..." : "Envoyer e-sign"} +
+ @@ -1524,7 +1595,7 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract onClick={() => setShowSalaryModal(true)} className="px-3 py-1 text-sm bg-green-600 text-white rounded hover:bg-green-700 transition-colors flex items-center gap-1" > - + Saisir brut - ))} diff --git a/public/simulateur-embed.html b/public/simulateur-embed.html index ed84158..41c9df0 100644 --- a/public/simulateur-embed.html +++ b/public/simulateur-embed.html @@ -1625,8 +1625,6 @@ document.getElementById('calcBtn').addEventListener('click', function() { timestamp: new Date().toISOString() } }, '*'); - - console.log('📊 PostHog: Événement simulateur_calculation enrichi envoyé'); } catch (e) { console.error('Erreur lors de l\'envoi de l\'événement PostHog:', e); }