Files
saju-web/app/compatibility/result/CompatibilityDetailUnlock.tsx

199 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. 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 } from 'react';
import { createBrowserClient } from '@supabase/ssr';
import { useRouter } from 'next/navigation';
import TokenPurchaseModal from '@/components/TokenPurchaseModal';
import { ensureProfile } from '@/lib/ensure-profile';
interface Props {
allPros: string[];
allCons: string[];
advice: string;
element1: string;
element2: string;
element1Kr: string;
element2Kr: string;
}
export default function CompatibilityDetailUnlock({ allPros, allCons, advice, element1, element2, element1Kr, element2Kr }: Props) {
const [isUnlocked, setIsUnlocked] = useState(false);
const [user, setUser] = useState<any>(null);
const [credits, setCredits] = useState(0);
const [showModal, setShowModal] = useState(false);
const [loading, setLoading] = useState(false);
const router = useRouter();
const supabase = createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
useEffect(() => {
const init = async () => {
const { data: { user } } = await supabase.auth.getUser();
if (user) {
setUser(user);
const currentCredits = await ensureProfile(supabase, user);
setCredits(currentCredits);
}
};
init();
}, []);
const handleUnlock = async () => {
if (!user) {
if (confirm('로그인이 필요합니다. 로그인 페이지로 이동하시겠습니까?')) {
router.push('/login');
}
return;
}
if (credits < 1) {
setShowModal(true);
return;
}
// 토큰 차감
setLoading(true);
const { error } = await supabase
.from('profiles')
.update({ credits: credits - 1 })
.eq('id', user.id);
if (error) {
alert('토큰 차감에 실패했습니다. 다시 시도해주세요.');
setLoading(false);
return;
}
setCredits(credits - 1);
setIsUnlocked(true);
setLoading(false);
};
const handlePurchaseComplete = async () => {
setShowModal(false);
// 크레딧 새로고침
if (user) {
const { data: profile } = await supabase
.from('profiles')
.select('credits')
.eq('id', user.id)
.single();
if (profile) setCredits(profile.credits || 0);
}
};
if (!isUnlocked) {
return (
<>
<div className="relative mb-8">
{/* 블러 처리된 미리보기 */}
<div className="filter blur-sm select-none pointer-events-none opacity-60">
<div className="grid md:grid-cols-2 gap-8 mb-8">
<div className="bg-white rounded-2xl shadow-lg p-8">
<h3 className="text-2xl font-bold text-gray-900 mb-4 flex items-center">
<span className="text-3xl mr-3"></span>
</h3>
<div className="space-y-3">
{allPros.slice(0, 3).map((_, i) => (
<div key={i} className="h-4 bg-gray-200 rounded w-full"></div>
))}
</div>
</div>
<div className="bg-white rounded-2xl shadow-lg p-8">
<h3 className="text-2xl font-bold text-gray-900 mb-4 flex items-center">
<span className="text-3xl mr-3"></span>
</h3>
<div className="space-y-3">
{allCons.slice(0, 3).map((_, i) => (
<div key={i} className="h-4 bg-gray-200 rounded w-full"></div>
))}
</div>
</div>
</div>
<div className="bg-gradient-to-r from-indigo-600 to-purple-600 rounded-2xl p-8">
<div className="h-6 bg-white/30 rounded w-3/4 mx-auto mb-4"></div>
<div className="h-4 bg-white/20 rounded w-full"></div>
</div>
</div>
{/* 잠금 오버레이 */}
<div className="absolute inset-0 flex items-center justify-center bg-white/40 backdrop-blur-[2px] rounded-2xl">
<div className="text-center p-8 bg-white/95 backdrop-blur-md rounded-2xl shadow-xl border border-pink-100 max-w-sm mx-auto">
<div className="text-4xl mb-4">🔐</div>
<h3 className="text-2xl font-bold text-gray-900 mb-2"> </h3>
<p className="text-gray-600 mb-2">
{element1Kr}({element1}) {element2Kr}({element2})<br />
.
</p>
<p className="text-sm text-gray-500 mb-4">
1 | : <span className="font-bold text-pink-600">{credits}</span>
</p>
<button
onClick={handleUnlock}
disabled={loading}
className="w-full bg-gradient-to-r from-pink-600 to-purple-600 text-white font-bold py-3 px-6 rounded-xl hover:shadow-lg hover:scale-105 transition transform disabled:opacity-50"
>
{loading ? '처리 중...' : credits >= 1 ? '토큰 1개로 잠금해제' : '토큰 충전하기'}
</button>
</div>
</div>
</div>
<TokenPurchaseModal
isOpen={showModal}
onClose={() => setShowModal(false)}
onPurchaseComplete={handlePurchaseComplete}
user={user}
supabase={supabase}
/>
</>
);
}
// Unlocked content
return (
<>
<div className="grid md:grid-cols-2 gap-8 mb-8">
<div className="bg-white rounded-2xl shadow-lg p-8">
<h3 className="text-2xl font-bold text-gray-900 mb-4 flex items-center">
<span className="text-3xl mr-3"></span>
</h3>
<ul className="space-y-3 text-gray-700">
{allPros.map((pro, i) => (
<li key={i} className="flex items-start">
<span className="text-pink-600 mr-2 mt-1 flex-shrink-0"></span>
<span>{pro}</span>
</li>
))}
</ul>
</div>
<div className="bg-white rounded-2xl shadow-lg p-8">
<h3 className="text-2xl font-bold text-gray-900 mb-4 flex items-center">
<span className="text-3xl mr-3"></span>
</h3>
<ul className="space-y-3 text-gray-700">
{allCons.map((con, i) => (
<li key={i} className="flex items-start">
<span className="text-purple-600 mr-2 mt-1 flex-shrink-0"></span>
<span>{con}</span>
</li>
))}
</ul>
</div>
</div>
<div className="bg-gradient-to-r from-indigo-600 to-purple-600 rounded-2xl shadow-lg p-8 text-white mb-8">
<h3 className="text-2xl font-bold mb-4 text-center">💡 </h3>
<p className="text-lg leading-relaxed text-center">{advice}</p>
<p className="text-sm text-white/70 mt-4 text-center">
. .
</p>
</div>
</>
);
}