185 lines
6 KiB
TypeScript
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>
|
|
);
|
|
}
|