218 lines
12 KiB
TypeScript
218 lines
12 KiB
TypeScript
import React from 'react';
|
||
import { db } from '@/lib/db';
|
||
import {
|
||
Terminal,
|
||
Copy,
|
||
Globe,
|
||
Webhook,
|
||
Zap,
|
||
ShieldCheck,
|
||
Code2,
|
||
Server,
|
||
Link as LinkIcon
|
||
} from 'lucide-react';
|
||
import { cookies } from 'next/headers';
|
||
import { redirect } from 'next/navigation';
|
||
import ApiKeyVisibilityToggle from '@/components/merchant/ApiKeyVisibilityToggle';
|
||
|
||
async function getMerchant(identifier: string) {
|
||
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(identifier);
|
||
|
||
const queryText = isUUID
|
||
? 'SELECT * FROM merchants WHERE id = $1 LIMIT 1'
|
||
: 'SELECT * FROM merchants WHERE short_id = $1 LIMIT 1';
|
||
|
||
const result = await db.query(queryText, [identifier]);
|
||
return result.rows[0];
|
||
}
|
||
|
||
export default async function MerchantIntegrationPage(props: {
|
||
params: Promise<{ id: string }>;
|
||
}) {
|
||
const resolvedParams = await props.params;
|
||
const identifier = resolvedParams.id;
|
||
const merchant = await getMerchant(identifier);
|
||
const cookieStore = await cookies();
|
||
|
||
if (!merchant) return null;
|
||
|
||
if (!cookieStore.get(`merchant_auth_${merchant.id}`)) {
|
||
redirect(`/merchant/${identifier}/login`);
|
||
}
|
||
|
||
const host = process.env.NEXT_PUBLIC_BASE_URL || 'https://p2cgateway.store';
|
||
const checkoutUrl = `${host}/checkout?merchant_id=${merchant.short_id || merchant.id}&amount=100¤cy=TRY&ref_id=SİPARİŞ_123`;
|
||
|
||
return (
|
||
<div className="max-w-6xl space-y-16 animate-in fade-in slide-in-from-bottom-4 duration-700 pb-32">
|
||
{/* Header */}
|
||
<div className="flex flex-col md:flex-row md:items-end justify-between gap-6">
|
||
<div>
|
||
<h1 className="text-4xl font-black text-gray-900 tracking-tight">Entegrasyon Rehberi</h1>
|
||
<p className="text-xs text-gray-400 font-black uppercase tracking-[0.3em] mt-3 px-1 border-l-4 border-blue-600 pl-4">Ödeme sistemini sisteminize dahil edin</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Methods Selection */}
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-10">
|
||
{/* Option 1: Quick Link */}
|
||
<div className="bg-white p-12 rounded-[48px] border border-gray-100 shadow-xl shadow-gray-100/50 space-y-10 relative overflow-hidden group">
|
||
<div className="absolute top-0 right-0 w-32 h-32 bg-blue-50 rounded-full -mr-16 -mt-16 group-hover:scale-150 transition-transform duration-700"></div>
|
||
|
||
<div className="space-y-6 relative">
|
||
<div className="w-16 h-16 bg-blue-600 rounded-3xl flex items-center justify-center text-white shadow-lg shadow-blue-200">
|
||
<LinkIcon size={32} />
|
||
</div>
|
||
<h2 className="text-2xl font-black text-gray-900">1. Hızlı Ödeme Linki</h2>
|
||
<p className="text-gray-500 font-medium leading-relaxed">
|
||
Kod yazmanıza gerek kalmadan, müşterilerinizi doğrudan ödeme sayfamıza yönlendirebilirsiniz. Parametreleri URL üzerinden iletebilirsiniz.
|
||
</p>
|
||
</div>
|
||
|
||
<div className="space-y-4">
|
||
<p className="text-[10px] font-black text-gray-400 uppercase tracking-widest pl-1">Örnek Yapı</p>
|
||
<div className="bg-gray-50 p-6 rounded-3xl border border-gray-100 font-mono text-[11px] text-gray-600 break-all leading-relaxed relative group/code">
|
||
{checkoutUrl}
|
||
<button className="absolute top-4 right-4 p-2 bg-white rounded-lg shadow-sm opacity-0 group-hover/code:opacity-100 transition-opacity">
|
||
<Copy size={14} className="text-gray-400" />
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Option 2: Server-to-Server API */}
|
||
<div className="bg-gray-900 p-12 rounded-[48px] shadow-2xl space-y-10 relative overflow-hidden group">
|
||
<div className="absolute top-0 right-0 w-32 h-32 bg-white/5 rounded-full -mr-16 -mt-16"></div>
|
||
|
||
<div className="space-y-6 relative">
|
||
<div className="w-16 h-16 bg-emerald-500 rounded-3xl flex items-center justify-center text-white shadow-lg shadow-emerald-900/20">
|
||
<Server size={32} />
|
||
</div>
|
||
<h2 className="text-2xl font-black text-white">2. Profesyonel API (v1)</h2>
|
||
<p className="text-gray-400 font-medium leading-relaxed">
|
||
Sunucu taraflı entegrasyon ile daha güvenli işlemler başlatın. Fiyat manipülasyonunu engeller ve sessiz oturumlar oluşturur.
|
||
</p>
|
||
</div>
|
||
|
||
<div className="space-y-4">
|
||
<p className="text-[10px] font-black text-gray-500 uppercase tracking-widest pl-1">Endpoint</p>
|
||
<div className="bg-white/5 p-6 rounded-3xl border border-white/10 font-mono text-[11px] text-emerald-400">
|
||
POST {host}/api/v1/checkout
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* API Details Section */}
|
||
<div className="bg-white p-12 rounded-[48px] border border-gray-100 shadow-sm space-y-12">
|
||
<div className="flex items-center gap-6">
|
||
<div className="w-14 h-14 bg-gray-50 rounded-2xl flex items-center justify-center text-gray-900">
|
||
<ShieldCheck size={28} />
|
||
</div>
|
||
<div>
|
||
<h3 className="text-2xl font-black text-gray-900">API Erişimi ve Güvenlik</h3>
|
||
<p className="text-xs text-gray-400 font-bold uppercase tracking-widest mt-1">İsteklerinizi doğrulamak için bu anahtarları kullanın</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-10">
|
||
<div className="space-y-4">
|
||
<label className="text-[10px] font-black text-gray-400 uppercase tracking-widest ml-2">Public Merchant ID</label>
|
||
<div className="bg-gray-50 p-5 rounded-2xl border border-gray-100 flex items-center justify-between">
|
||
<code className="text-xs font-mono font-bold text-gray-600 truncate">{merchant.id}</code>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-4">
|
||
<label className="text-[10px] font-black text-gray-400 uppercase tracking-widest ml-2">Secure API Secret Key</label>
|
||
<ApiKeyVisibilityToggle apiKey={merchant.api_key} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Webhook & Payout Addresses */}
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-10">
|
||
{/* Webhook Settings */}
|
||
<div className="bg-white p-12 rounded-[48px] border border-gray-100 shadow-sm space-y-12">
|
||
<div className="flex items-center gap-6">
|
||
<div className="w-14 h-14 bg-purple-50 rounded-2xl flex items-center justify-center text-purple-600">
|
||
<Webhook size={28} />
|
||
</div>
|
||
<div>
|
||
<h3 className="text-2xl font-black text-gray-900">Webhooks</h3>
|
||
<p className="text-xs text-gray-400 font-bold uppercase tracking-widest mt-1">Anlık Bildirimler</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-8">
|
||
<div className="p-8 bg-gray-50 rounded-[32px] border border-gray-100 space-y-6">
|
||
<div className="flex items-center justify-between">
|
||
<span className="text-[11px] font-black text-gray-400 uppercase tracking-widest ml-2">URL</span>
|
||
<span className={`text-[10px] font-black px-3 py-1 rounded-full ${merchant.webhook_url ? 'bg-emerald-100 text-emerald-700' : 'bg-red-100 text-red-700'}`}>
|
||
{merchant.webhook_url ? 'AKTİF' : 'TANIMSZ'}
|
||
</span>
|
||
</div>
|
||
<div className="bg-white p-6 rounded-2xl border border-gray-200">
|
||
<code className="text-sm font-bold text-gray-700 break-all">
|
||
{merchant.webhook_url || 'https://siteniz.com/callback'}
|
||
</code>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Payout Addresses */}
|
||
<div className="bg-white p-12 rounded-[48px] border border-gray-100 shadow-sm space-y-12">
|
||
<div className="flex items-center gap-6">
|
||
<div className="w-14 h-14 bg-emerald-50 rounded-2xl flex items-center justify-center text-emerald-600">
|
||
<Zap size={28} />
|
||
</div>
|
||
<div>
|
||
<h3 className="text-2xl font-black text-gray-900">Hak Ediş Adresleriniz</h3>
|
||
<p className="text-xs text-gray-400 font-bold uppercase tracking-widest mt-1">Ödemeleriniz bu adreslere iletilir</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-4">
|
||
{['EVM', 'SOLANA', 'TRON', 'BITCOIN'].map((net) => {
|
||
const addr = merchant.payout_addresses?.[net] || (net === 'EVM' ? merchant.payout_address : null);
|
||
return (
|
||
<div key={net} className="flex items-center justify-between p-4 bg-gray-50 rounded-2xl border border-gray-100 group">
|
||
<div className="flex items-center gap-3">
|
||
<div className={`w-8 h-8 rounded-xl flex items-center justify-center text-white text-[10px] font-black ${net === 'SOLANA' ? 'bg-emerald-500' : net === 'POLYGON' ? 'bg-purple-500' : net === 'TRON' ? 'bg-red-500' : 'bg-orange-500'}`}>
|
||
{net.slice(0, 1)}
|
||
</div>
|
||
<div>
|
||
<p className="text-[9px] font-black text-gray-400 uppercase tracking-[0.2em]">{net}</p>
|
||
<p className="text-[11px] font-mono font-bold text-gray-900 truncate max-w-[180px] lg:max-w-[250px]">
|
||
{addr || 'TANIMLANMAMIŞ'}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
{addr && <Copy size={14} className="text-gray-300 cursor-pointer hover:text-blue-600 transition" />}
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Footer Resources */}
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||
{[
|
||
{ title: 'Postman Koleksiyonu', icon: Terminal, color: 'blue' },
|
||
{ title: 'Geliştirici Dokümanları', icon: Code2, color: 'emerald' },
|
||
{ title: 'Teknik Yardım', icon: Globe, color: 'gray' },
|
||
].map((r) => (
|
||
<div key={r.title} className="bg-white p-8 rounded-[32px] border border-gray-100 shadow-sm flex items-center gap-6 hover:shadow-lg transition-all cursor-pointer group hover:-translate-y-1">
|
||
<div className={`w-14 h-14 bg-gray-50 rounded-2xl flex items-center justify-center text-gray-400 group-hover:bg-blue-600 group-hover:text-white transition-all`}>
|
||
<r.icon size={24} />
|
||
</div>
|
||
<span className="text-sm font-black text-gray-900 uppercase tracking-tight">{r.title}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|