'use client' import { useState, useEffect } from 'react' import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter, } from '@/components/ui/dialog' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { CircleDollarSign, Github, Heart, MessageSquare, Star, Coins, Check, Copy, } from 'lucide-react' import Link from 'next/link' import { ExternalLinks } from '@/config/external-links' import { CRYPTO_ADDRESSES } from '@/lib/constants' import Image from 'next/image' import { ApiEndpoints } from '@/config/api' import httpBrowserClient from '@/lib/httpBrowserClient' import { useQuery } from '@tanstack/react-query' // Add constants for localStorage and timing const STORAGE_KEYS = { LAST_SHOWN: 'contribute_modal_last_shown', HAS_CONTRIBUTED: 'contribute_modal_has_contributed', } const SHOW_INTERVAL = 1 * 24 * 60 * 60 * 1000 // 1 days in milliseconds const RANDOM_CHANCE = 0.3 // 30% chance to show when eligible export function ContributeModal() { const [isOpen, setIsOpen] = useState(false) const [cryptoOpen, setCryptoOpen] = useState(false) const [copiedAddress, setCopiedAddress] = useState('') const copyToClipboard = (address: string) => { navigator.clipboard.writeText(address) setCopiedAddress(address) setTimeout(() => setCopiedAddress(''), 3000) } const { data: currentPlan, isLoading: isLoadingPlan, error: planError, } = useQuery({ queryKey: ['currentPlan'], queryFn: () => httpBrowserClient .get(ApiEndpoints.billing.currentPlan()) .then((res) => res.data), }) useEffect(() => { const checkAndShowModal = () => { if (isLoadingPlan) return if (planError) return if (currentPlan?.name?.toLowerCase() !== 'free') { return } const hasContributed = localStorage.getItem(STORAGE_KEYS.HAS_CONTRIBUTED) === 'true' if (hasContributed) return setIsOpen(true) return; const lastShown = localStorage.getItem(STORAGE_KEYS.LAST_SHOWN) const now = Date.now() if (!lastShown || now - parseInt(lastShown) >= SHOW_INTERVAL) { if (Math.random() < RANDOM_CHANCE) { setIsOpen(true) localStorage.setItem(STORAGE_KEYS.LAST_SHOWN, now.toString()) } } } checkAndShowModal() document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') { checkAndShowModal() } }) }, [currentPlan?.name, isLoadingPlan, planError]) const handleContributed = () => { localStorage.setItem(STORAGE_KEYS.HAS_CONTRIBUTED, 'true') setIsOpen(false) } return ( <> Support textbee.dev Your contribution helps keep this project alive and growing. Financial Support Monthly Support on Patreon One-time Donation via Polar.sh setCryptoOpen(true)} > Donate Cryptocurrency Code Contributions Star on GitHub Report Issue I've already donated setIsOpen(false)}> Remind me later Donate Cryptocurrency {CRYPTO_ADDRESSES.map((wallet, index) => ( {wallet.name} {wallet.network} copyToClipboard(wallet.address)} > {copiedAddress === wallet.address ? ( ) : ( )} {wallet.address} ))} > ) }
{wallet.name}
{wallet.network}
{wallet.address}