WIP: modifs sur Mac Mini
This commit is contained in:
parent
74aa268603
commit
ea06d4c982
10 changed files with 179 additions and 62 deletions
|
|
@ -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
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
101
app/api/staff/contrats/[id]/employee-email/route.ts
Normal file
101
app/api/staff/contrats/[id]/employee-email/route.ts
Normal file
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|||
<FileSignature className="w-4 h-4" />
|
||||
{isGeneratingESign ? "Envoi..." : "Envoyer e-sign"}
|
||||
</button>
|
||||
<div className="border-t border-gray-200 my-1"></div>
|
||||
<button
|
||||
onClick={() => {
|
||||
handleBulkReminderClick();
|
||||
setShowESignMenu(false);
|
||||
}}
|
||||
disabled={isLoadingReminder}
|
||||
className="w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors disabled:text-gray-400 disabled:hover:bg-white flex items-center gap-2"
|
||||
>
|
||||
<BellRing className="w-4 h-4" />
|
||||
{isLoadingReminder ? "Envoi..." : "Relancer salariés"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
|
@ -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"
|
||||
>
|
||||
<DollarSign className="w-4 h-4" />
|
||||
<Euro className="w-4 h-4" />
|
||||
Saisir brut
|
||||
</button>
|
||||
<button
|
||||
|
|
@ -1570,7 +1641,6 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract
|
|||
<th className="text-left px-3 py-2 cursor-pointer" onClick={() => { setSortField('end_date'); setSortOrder((o) => o === 'asc' ? 'desc' : 'asc'); }}>
|
||||
Date fin {sortField === 'end_date' ? (sortOrder === 'asc' ? '▲' : '▼') : ''}
|
||||
</th>
|
||||
<th className="text-left px-3 py-2">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -1673,16 +1743,6 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract
|
|||
}</td>
|
||||
<td className="px-3 py-2">{formatDate(r.start_date)}</td>
|
||||
<td className="px-3 py-2">{formatDate(r.end_date)}</td>
|
||||
<td className="px-3 py-2">
|
||||
<button
|
||||
onClick={() => handleReminderClick(r)}
|
||||
className="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-white bg-indigo-600 rounded hover:bg-indigo-700 transition-colors"
|
||||
title="Relancer le salarié"
|
||||
>
|
||||
<BellRing className="w-3.5 h-3.5" />
|
||||
Relancer
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue