import { useEffect, useState } from 'react'; import type { RoadmapDocument } from './CreateRoadmap/CreateRoadmapModal'; import { formatCommaNumber } from '../../lib/number'; import { Rating } from '../Rating/Rating'; import { httpGet, httpPost } from '../../lib/http'; import { useToast } from '../../hooks/use-toast'; import { isLoggedIn } from '../../lib/jwt'; import { Loader2, Star } from 'lucide-react'; import { cn } from '../../lib/classname'; import { showLoginPopup } from '../../lib/popup'; import { Spinner } from '../ReactIcons/Spinner.tsx'; type GetMyRoadmapRatingResponse = { id?: string; rating: number; feedback?: string; }; type RateRoadmapFormProps = { ratings: RoadmapDocument['ratings']; roadmapSlug: string; canManage?: boolean; }; export function RateRoadmapForm(props: RateRoadmapFormProps) { const { ratings, canManage = false, roadmapSlug } = props; const { breakdown = {}, average: _average } = ratings || {}; const average = _average || 0; const ratingsKeys = [5, 4, 3, 2, 1]; const totalRatings = ratingsKeys.reduce( (total, rating) => total + breakdown?.[rating] || 0, 0, ); // if no rating then only show the ratings breakdown if the user can manage the roadmap const showRatingsBreakdown = average > 0 || canManage; const toast = useToast(); const [isLoading, setIsLoading] = useState(true); const [isSubmitting, setIsSubmitting] = useState(false); const [isRatingRoadmap, setIsRatingRoadmap] = useState(!showRatingsBreakdown); const [userRatingId, setUserRatingId] = useState(); const [userRating, setUserRating] = useState(0); const [userFeedback, setUserFeedback] = useState(''); const loadMyRoadmapRating = async () => { // user can't have the rating for their own roadmap if (canManage) { setIsLoading(false); return; } const { response, error } = await httpGet( `${import.meta.env.PUBLIC_API_URL}/v1-get-my-roadmap-rating/${roadmapSlug}`, ); if (!response || error) { toast.error(error?.message || 'Something went wrong'); setIsLoading(false); return; } setUserRatingId(response?.id); setUserRating(response?.rating); setUserFeedback(response?.feedback || ''); setIsLoading(false); }; const submitMyRoadmapRating = async () => { if (userRating <= 0) { toast.error('At least give it a star'); return; } setIsSubmitting(true); const path = userRatingId ? 'v1-update-custom-roadmap-rating' : 'v1-rate-custom-roadmap'; const { response, error } = await httpPost<{ id: string; }>(`${import.meta.env.PUBLIC_API_URL}/${path}/${roadmapSlug}`, { rating: userRating, feedback: userFeedback, }); if (!response || error) { toast.error(error?.message || 'Something went wrong'); setIsSubmitting(false); return; } window.location.reload(); }; useEffect(() => { if (!isLoggedIn() || !roadmapSlug) { setIsLoading(false); return; } loadMyRoadmapRating().then(); }, [roadmapSlug]); return (
{showRatingsBreakdown && !isRatingRoadmap && ( <>
    {ratingsKeys.map((rating) => { const percentage = totalRatings <= 0 ? 0 : ((breakdown?.[rating] || 0) / totalRatings) * 100; return (
  • {rating} star
    {percentage > 0 && ( {formatCommaNumber(breakdown?.[rating] || 0)} )}
    {parseInt(`${percentage}`, 10)}%
  • ); })}
)} {!canManage && !isRatingRoadmap && (
{isLoading && (
)} {!isLoading && !isRatingRoadmap && !userRatingId && ( <>

Rate and share your thoughts with the roadmap creator.

)} {!isLoading && !isRatingRoadmap && userRatingId && (

Your Feedback

( {userRating})
{userFeedback &&

{userFeedback}

}
)}
)} {!canManage && isRatingRoadmap && (

Rate this roadmap

Share your thoughts with the roadmap creator.

{ e.preventDefault(); submitMyRoadmapRating().then(); }} > { setUserRating(rating); }} starSize={32} />