Files
cbd420/app/components/UnlockModal.tsx
2025-12-22 06:43:19 +01:00

295 lines
8.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useState, useEffect, Suspense } from 'react'
import AuthModal from './AuthModal'
import { useI18n } from '@/lib/i18n'
interface UnlockModalProps {
isOpen: boolean
onClose: () => void
}
interface User {
id: number
username: string
email: string
}
interface ReferralStatus {
referralCount: number
isUnlocked: boolean
referralsNeeded: number
referralsRemaining: number
}
export default function UnlockModal({ isOpen, onClose }: UnlockModalProps) {
const { t } = useI18n()
const [referralStatus, setReferralStatus] = useState<ReferralStatus | null>(null)
const [referralLink, setReferralLink] = useState<string>('')
const [loading, setLoading] = useState(true)
const [copied, setCopied] = useState(false)
const [showAuthModal, setShowAuthModal] = useState(false)
useEffect(() => {
if (isOpen) {
fetchReferralData()
}
}, [isOpen])
const fetchReferralData = async () => {
setLoading(true)
try {
// Fetch referral status
const statusResponse = await fetch('/api/referrals/status', {
credentials: 'include',
})
const statusData = await statusResponse.json()
setReferralStatus(statusData)
// Fetch referral link if user is logged in
const linkResponse = await fetch('/api/referrals/link', {
credentials: 'include',
})
if (linkResponse.ok) {
const linkData = await linkResponse.json()
setReferralLink(linkData.referralLink)
}
} catch (error) {
console.error('Error fetching referral data:', error)
} finally {
setLoading(false)
}
}
const handleCopyLink = async () => {
if (!referralLink) return
try {
await navigator.clipboard.writeText(referralLink)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
} catch (error) {
console.error('Failed to copy link:', error)
}
}
const handleLogin = async (user: User) => {
setShowAuthModal(false)
// Refresh referral data after login
await fetchReferralData()
}
if (!isOpen) return null
const status = referralStatus || {
referralCount: 0,
isUnlocked: false,
referralsNeeded: 3,
referralsRemaining: 3,
}
return (
<div
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'rgba(0, 0, 0, 0.7)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: 1000,
padding: '20px',
}}
onClick={onClose}
>
<div
style={{
background: 'var(--card)',
borderRadius: '16px',
padding: '32px',
maxWidth: '500px',
width: '100%',
boxShadow: '0 20px 60px rgba(0, 0, 0, 0.3)',
}}
onClick={(e) => e.stopPropagation()}
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '24px' }}>
<h2 style={{ margin: 0 }}>{t('unlockModal.title')}</h2>
<button
onClick={onClose}
style={{
background: 'transparent',
border: 'none',
fontSize: '24px',
cursor: 'pointer',
color: 'var(--muted)',
padding: 0,
width: '32px',
height: '32px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
×
</button>
</div>
{loading ? (
<p style={{ color: 'var(--muted)', textAlign: 'center' }}>{t('common.loading')}</p>
) : (
<>
<div style={{ marginBottom: '24px', textAlign: 'center' }}>
<div style={{ fontSize: '18px', marginBottom: '8px' }}>
🔒 {t('unlockModal.referralsCompleted', { count: status.referralCount, needed: status.referralsNeeded })}
</div>
<p style={{ color: 'var(--muted)', fontSize: '14px', margin: '8px 0' }}>
{t('unlockModal.inviteFriends', { needed: status.referralsNeeded })}
<br />
{t('unlockModal.unlockForever')}
</p>
</div>
{referralLink ? (
<div style={{ marginBottom: '24px' }}>
<label
style={{
display: 'block',
marginBottom: '8px',
fontSize: '14px',
color: 'var(--muted)',
fontWeight: 500,
}}
>
{t('unlockModal.yourReferralLink')}
</label>
<div style={{ display: 'flex', gap: '8px' }}>
<input
type="text"
value={referralLink}
readOnly
style={{
flex: 1,
padding: '12px',
borderRadius: '8px',
border: '1px solid var(--border)',
background: 'var(--bg-soft)',
color: 'var(--text)',
fontSize: '14px',
fontFamily: 'monospace',
}}
/>
<button
onClick={handleCopyLink}
style={{
padding: '12px 20px',
background: copied ? 'var(--accent)' : 'var(--bg-soft)',
border: '1px solid var(--border)',
borderRadius: '8px',
color: copied ? '#000' : 'var(--text)',
cursor: 'pointer',
fontSize: '14px',
fontWeight: 500,
whiteSpace: 'nowrap',
}}
>
{copied ? t('unlockModal.copied') : t('unlockModal.copyLink')}
</button>
</div>
</div>
) : (
<div
style={{
padding: '16px',
background: 'var(--bg-soft)',
borderRadius: '8px',
marginBottom: '24px',
textAlign: 'center',
}}
>
<p style={{ color: 'var(--muted)', fontSize: '14px', margin: '0 0 12px 0' }}>
{t('unlockModal.yourReferralLink')}
</p>
<button
onClick={() => setShowAuthModal(true)}
style={{
padding: '10px 20px',
background: 'var(--accent)',
color: '#000',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
fontSize: '14px',
fontWeight: 500,
}}
>
{t('auth.login')}
</button>
</div>
)}
<div
style={{
padding: '12px',
background: 'var(--bg-soft)',
borderRadius: '8px',
marginBottom: '24px',
fontSize: '13px',
color: 'var(--muted)',
textAlign: 'center',
}}
>
{t('unlockModal.friendsMustSignUp')}
</div>
<div
style={{
textAlign: 'center',
fontSize: '16px',
fontWeight: 500,
color: 'var(--text)',
marginBottom: '24px',
}}
>
{status.referralsRemaining === 1
? t('unlockModal.referralsToGoSingular', { remaining: status.referralsRemaining })
: t('unlockModal.referralsToGoPlural', { remaining: status.referralsRemaining })
}
</div>
<button
onClick={onClose}
style={{
width: '100%',
padding: '12px 24px',
background: 'var(--accent)',
color: '#000',
border: 'none',
borderRadius: '14px',
cursor: 'pointer',
fontSize: '15px',
fontWeight: 500,
}}
>
{t('common.close')}
</button>
</>
)}
</div>
{/* Auth Modal */}
<Suspense fallback={null}>
<AuthModal
isOpen={showAuthModal}
onClose={() => setShowAuthModal(false)}
onLogin={handleLogin}
/>
</Suspense>
</div>
)
}