'use client' import { Badge } from '@thedaviddias/design-system/badge' import { Star } from 'lucide-react' import { useEffect, useRef, useState } from 'react' import { getUserContributions } from '@/lib/github-contributions' interface ContributionBadgeProps { username: string } /** * Displays a contributor badge for users with GitHub contributions */ export function ContributionBadge({ username }: ContributionBadgeProps) { const [isContributor, setIsContributor] = useState(null) const [isLoading, setIsLoading] = useState(false) const [isVisible, setIsVisible] = useState(false) const elementRef = useRef(null) // Use Intersection Observer to lazy load contribution data useEffect(() => { // Check if IntersectionObserver is available (not in SSR/jsdom) if (typeof window === 'undefined' || !('IntersectionObserver' in window)) { // Fallback: set visibility immediately if IntersectionObserver is not available setIsVisible(true) return } const observer = new IntersectionObserver( entries => { const entry = entries[0] if (entry.isIntersecting && !isLoading && isContributor === null) { setIsVisible(true) } }, { root: null, rootMargin: '50px', // Start loading slightly before the element is visible threshold: 0.01 } ) if (elementRef.current) { observer.observe(elementRef.current) } return () => { // Clean up observer to prevent memory leaks observer.disconnect() } }, [isLoading, isContributor]) // Fetch contribution data when visible useEffect(() => { if (!isVisible || isLoading || isContributor !== null) return /** * Fetches contribution data for the given username */ const fetchContributions = async () => { setIsLoading(true) try { const contributions = await getUserContributions(username) setIsContributor(contributions.total > 0) } catch (_error) { // On error, assume not a contributor setIsContributor(false) } finally { setIsLoading(false) } } fetchContributions() }, [isVisible, username, isLoading, isContributor]) return (
{isLoading && (
Checking... )} {isContributor === true && ( Contributor )}
) }