espace-paie-odentas/components/surveys/ContractCreationSurvey.tsx

185 lines
6 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { usePostHog } from 'posthog-js/react';
import { Star, X } from 'lucide-react';
interface ContractCreationSurveyProps {
isOpen: boolean;
onClose: () => void;
contractId?: string;
contractType?: 'CDDU' | 'RG';
}
/**
* Survey de satisfaction après création d'un contrat
*
* @example
* ```tsx
* const [showSurvey, setShowSurvey] = useState(false);
* const [contractId, setContractId] = useState<string>();
*
* // Après création réussie du contrat :
* setContractId(result.contract.id);
* setShowSurvey(true);
*
* // Dans le JSX :
* <ContractCreationSurvey
* isOpen={showSurvey}
* onClose={() => setShowSurvey(false)}
* contractId={contractId}
* contractType="CDDU"
* />
* ```
*/
export function ContractCreationSurvey({
isOpen,
onClose,
contractId,
contractType,
}: ContractCreationSurveyProps) {
const posthog = usePostHog();
const [rating, setRating] = useState<number | null>(null);
const [hoverRating, setHoverRating] = useState<number | null>(null);
const [feedback, setFeedback] = useState('');
const [submitted, setSubmitted] = useState(false);
const [showFeedback, setShowFeedback] = useState(false);
useEffect(() => {
if (rating !== null && rating <= 3) {
setShowFeedback(true);
} else {
setShowFeedback(false);
setFeedback('');
}
}, [rating]);
if (!isOpen) return null;
const handleSubmit = () => {
if (rating) {
posthog?.capture('contract_creation_survey_submitted', {
rating,
feedback: feedback.trim() || undefined,
contract_id: contractId,
contract_type: contractType,
timestamp: new Date().toISOString(),
});
console.log('📊 Survey soumis:', { rating, feedback, contractId, contractType });
setSubmitted(true);
setTimeout(() => {
onClose();
// Reset pour la prochaine fois
setTimeout(() => {
setRating(null);
setFeedback('');
setSubmitted(false);
setShowFeedback(false);
}, 500);
}, 2000);
}
};
const handleDismiss = () => {
posthog?.capture('contract_creation_survey_dismissed', {
had_rating: rating !== null,
contract_id: contractId,
contract_type: contractType,
});
onClose();
};
return (
<div className="fixed bottom-4 right-4 z-50 w-96 bg-white rounded-xl shadow-2xl border border-slate-200 animate-in slide-in-from-bottom-4 duration-300">
{!submitted ? (
<div className="p-6">
<button
onClick={handleDismiss}
className="absolute top-3 right-3 text-slate-400 hover:text-slate-600 transition"
aria-label="Fermer"
>
<X className="w-5 h-5" />
</button>
<h3 className="text-lg font-semibold mb-2 pr-8">📊 Votre avis compte !</h3>
<p className="text-sm text-slate-600 mb-4">
Comment évaluez-vous la facilité du processus de création de contrat ?
</p>
{/* Stars rating */}
<div className="flex justify-center gap-2 mb-4">
{[1, 2, 3, 4, 5].map((star) => (
<button
key={star}
onClick={() => setRating(star)}
onMouseEnter={() => setHoverRating(star)}
onMouseLeave={() => setHoverRating(null)}
className="transition-all hover:scale-110 focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-offset-2 rounded"
aria-label={`${star} étoile${star > 1 ? 's' : ''}`}
>
<Star
className={`w-8 h-8 transition-colors ${
(hoverRating || rating || 0) >= star
? 'fill-yellow-400 text-yellow-400'
: 'text-slate-300'
}`}
/>
</button>
))}
</div>
<div className="flex justify-between text-xs text-slate-500 mb-4">
<span>Très difficile</span>
<span>Très facile</span>
</div>
{/* Feedback optionnel si note <= 3 */}
{showFeedback && (
<div className="mb-4 animate-in slide-in-from-top-2 duration-200">
<label className="block text-sm font-medium text-slate-700 mb-2">
Que pourrions-nous améliorer ? (optionnel)
</label>
<textarea
value={feedback}
onChange={(e) => setFeedback(e.target.value)}
placeholder="Partagez vos suggestions..."
className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 focus:border-transparent resize-none"
rows={3}
maxLength={500}
/>
<p className="text-xs text-slate-500 mt-1">
{feedback.length}/500 caractères
</p>
</div>
)}
<div className="flex gap-2">
<button
onClick={handleDismiss}
className="flex-1 py-2 px-4 border border-slate-300 text-slate-700 rounded-lg hover:bg-slate-50 transition text-sm font-medium"
>
Plus tard
</button>
<button
onClick={handleSubmit}
disabled={!rating}
className="flex-1 py-2 px-4 bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 disabled:opacity-50 disabled:cursor-not-allowed transition text-sm font-medium"
>
Envoyer
</button>
</div>
</div>
) : (
<div className="p-6 text-center animate-in fade-in duration-200">
<div className="mb-3 text-4xl"></div>
<h3 className="text-lg font-semibold mb-1">Merci !</h3>
<p className="text-sm text-slate-600">
Votre retour nous aide à améliorer l'application.
</p>
</div>
)}
</div>
);
}