stripe changes

This commit is contained in:
2026-01-05 09:37:20 +01:00
parent d04d9d9887
commit 8f863153cb
5 changed files with 241 additions and 60 deletions

View File

@@ -9,7 +9,8 @@ import {
AlertTriangle, Archive, Send, Layout, History, MessageCircle, Info, ChevronDown, ChevronUp,
Upload, FileDown, Receipt, CreditCard, DollarSign, Plus, Trash2, Building2, User as UserIcon,
Palette, Zap, Lightbulb, Link as LinkIcon, ExternalLink, Target, FileStack, Star, Check,
Copy, Cpu, Wand2, Eye, EyeOff, ShieldCheck, Calendar, Search, ArrowUpDown, Filter
Copy, Cpu, Wand2, Eye, EyeOff, ShieldCheck, Calendar, Search, ArrowUpDown, Filter,
TrendingUp, ArrowRight
} from 'lucide-react';
import { Button } from '../components/Button';
import { supabase, isSupabaseConfigured } from '../lib/supabaseClient';
@@ -57,6 +58,7 @@ interface AdminOrder {
status: string;
date: string;
amount: string;
created_at: string;
details?: any;
history?: OrderHistoryEntry[];
emailLogs?: EmailLogEntry[];
@@ -157,8 +159,8 @@ const getEmailTemplate = (type: string, data: {
body: `<div style="${baseStyle}">
<div style="${headerStyle}">MotionWeb</div>
<p>Kedves <strong>${data.customer}</strong>!</p>
<p>Köszönöm a visszajelzését a <strong>${data.package}</strong> demó verziójával kapcsolatban.</p>
<p>A kért módosításokat feldolgoztam, és megkezdtem azok átvezetését a weboldalon. Amint elkészültem a frissített verzióval, e-mailben értesítem.</p>
<p>Köszönöm a visszajelzéseit! Megkezdtem a kért módosítások átvezetését a weboldalon.</p>
<p>Hamarosan jelentkezem a frissített verzióval.</p>
<div style="${footerStyle}">Üdvözlettel,<br><strong>Balogh Bence Benedek</strong><br>MotionWeb | motionweb.hu</div>
</div>`
},
@@ -495,9 +497,7 @@ export const Admin: React.FC = () => {
try {
if (typeof e === 'string') errorMessage = e;
else if (e instanceof Error) errorMessage = e.message;
else if (typeof e === 'object' && e !== null) {
errorMessage = e.message || e.error_description || JSON.stringify(e);
}
else if (typeof e === 'object') errorMessage = JSON.stringify(e);
} catch (jsonErr) {
errorMessage = "Nem szerializálható hiba objektum";
}
@@ -583,22 +583,35 @@ export const Admin: React.FC = () => {
return;
}
// Generate Stripe Link
const { data: checkoutData, error: checkoutError } = await supabase.functions.invoke('create-checkout-session', {
body: {
order_id: sub.order_id,
package_name: 'Maintenance',
payment_type: 'annual',
customer_email: sub.client_email
}
});
if (checkoutError || !checkoutData?.url) {
throw new Error('Nem sikerült generálni a fizetési linket.');
}
const paymentLink = checkoutData.url;
const daysLeft = getDaysRemaining(sub.next_billing_date);
const emailType = 'Előfizetés emlékeztető';
const nowIso = new Date().toISOString();
// Placeholder payment link
const paymentLink = "https://stripe.com/payment_placeholder";
const orderData = sub.order as any; // Cast to avoid TS issues if types aren't perfect
const customerName = orderData?.customer_name || 'Ügyfél';
const customerEmail = sub.client_email || orderData?.customer_email;
const domain = orderData?.details?.domainName;
const amount = "59 990 Ft"; // Or use orderData.amount if applicable
const amount = "59 990 Ft";
const template = getEmailTemplate(emailType, {
customer: customerName,
package: 'Fenntartás', // Dummy package name for template type signature
package: 'Fenntartás',
domain: domain,
daysLeft: daysLeft,
paymentLink: paymentLink,
@@ -927,22 +940,162 @@ export const Admin: React.FC = () => {
</div>
<div className="animate-fade-in">
{activeTab === 'overview' && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 md:gap-8">
<div className="bg-white p-8 rounded-[32px] border border-gray-100 shadow-sm">
<p className="text-xs font-bold text-gray-400 uppercase mb-3 tracking-widest">Látogatók</p>
<h3 className="text-4xl md:text-5xl font-black text-gray-900">{visitorStats.month}</h3>
{activeTab === 'overview' && (() => {
// -- Statistics Logic Calculation inside render for Overview Tab --
const orderStats = {
new: orders.filter(o => o.status === 'new').length,
inProgress: orders.filter(o => o.status === 'in_progress').length,
feedback: orders.filter(o => ['pending_feedback', 'waiting_feedback'].includes(o.status)).length,
completed: orders.filter(o => o.status === 'completed').length
};
const activeSubs = subscriptions.filter(s => s.status === 'active').length;
// Generate Yearly Chart Data
const currentYear = new Date().getFullYear();
const monthlyOrders = Array(12).fill(0);
orders.forEach(o => {
const d = new Date(o.created_at);
if (d.getFullYear() === currentYear) {
monthlyOrders[d.getMonth()]++;
}
});
const maxOrderCount = Math.max(...monthlyOrders, 1); // Avoid div by zero
const monthLabels = ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún', 'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'];
return (
<div className="space-y-8">
<div className="flex items-center gap-3 mb-2">
<h3 className="text-xl font-black text-gray-900 tracking-tight">Statisztika & Elemzés</h3>
<div className="h-px bg-gray-200 flex-grow"></div>
</div>
{/* Visitors Section */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="bg-gradient-to-br from-blue-50 to-white p-6 rounded-[28px] border border-blue-100 shadow-sm relative overflow-hidden group">
<div className="absolute right-0 top-0 w-24 h-24 bg-blue-100 rounded-full blur-2xl -mr-10 -mt-10 group-hover:bg-blue-200 transition-colors"></div>
<div className="relative z-10">
<div className="flex items-center gap-3 mb-4">
<div className="p-2 bg-blue-100 rounded-xl text-blue-600"><Users className="w-5 h-5" /></div>
<span className="text-xs font-black text-blue-800 uppercase tracking-widest">Heti Látogatók</span>
</div>
<h3 className="text-4xl font-black text-gray-900">{visitorStats.week}</h3>
<p className="text-[10px] text-gray-400 font-bold mt-2 uppercase tracking-wide">Aktuális hét</p>
</div>
</div>
<div className="bg-gradient-to-br from-purple-50 to-white p-6 rounded-[28px] border border-purple-100 shadow-sm relative overflow-hidden group">
<div className="absolute right-0 top-0 w-24 h-24 bg-purple-100 rounded-full blur-2xl -mr-10 -mt-10 group-hover:bg-purple-200 transition-colors"></div>
<div className="relative z-10">
<div className="flex items-center gap-3 mb-4">
<div className="p-2 bg-purple-100 rounded-xl text-purple-600"><Calendar className="w-5 h-5" /></div>
<span className="text-xs font-black text-purple-800 uppercase tracking-widest">Havi Látogatók</span>
</div>
<h3 className="text-4xl font-black text-gray-900">{visitorStats.month}</h3>
<p className="text-[10px] text-gray-400 font-bold mt-2 uppercase tracking-wide">Becsült aktivitás</p>
</div>
</div>
<div className="bg-gradient-to-br from-gray-50 to-white p-6 rounded-[28px] border border-gray-200 shadow-sm relative overflow-hidden group">
<div className="absolute right-0 top-0 w-24 h-24 bg-gray-100 rounded-full blur-2xl -mr-10 -mt-10 group-hover:bg-gray-200 transition-colors"></div>
<div className="relative z-10">
<div className="flex items-center gap-3 mb-4">
<div className="p-2 bg-gray-200 rounded-xl text-gray-600"><Globe className="w-5 h-5" /></div>
<span className="text-xs font-black text-gray-600 uppercase tracking-widest">Összes Látogató</span>
</div>
<h3 className="text-4xl font-black text-gray-900">{visitorStats.month}</h3>
<p className="text-[10px] text-gray-400 font-bold mt-2 uppercase tracking-wide">Indulás óta</p>
</div>
</div>
</div>
{/* Orders Funnel & Active Subs */}
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
{/* Funnel */}
<div className="lg:col-span-3 bg-white p-8 rounded-[32px] border border-gray-100 shadow-sm">
<h4 className="text-sm font-black text-gray-900 uppercase tracking-widest mb-6 flex items-center gap-2">
<Activity className="w-4 h-4 text-primary" /> Rendelési Folyamat
</h4>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div className="p-5 rounded-2xl bg-blue-50 border border-blue-100 flex flex-col justify-between h-32 relative overflow-hidden">
<div className="absolute right-2 top-2 opacity-10"><ShoppingCart className="w-16 h-16 text-blue-600" /></div>
<span className="text-xs font-black text-blue-600 uppercase tracking-widest">Új Rendelés</span>
<div className="flex items-end justify-between">
<h3 className="text-3xl font-black text-blue-900">{orderStats.new}</h3>
<ArrowRight className="w-5 h-5 text-blue-300" />
</div>
</div>
<div className="p-5 rounded-2xl bg-yellow-50 border border-yellow-100 flex flex-col justify-between h-32 relative overflow-hidden">
<div className="absolute right-2 top-2 opacity-10"><RefreshCw className="w-16 h-16 text-yellow-600" /></div>
<span className="text-xs font-black text-yellow-600 uppercase tracking-widest">Folyamatban</span>
<div className="flex items-end justify-between">
<h3 className="text-3xl font-black text-yellow-900">{orderStats.inProgress}</h3>
<ArrowRight className="w-5 h-5 text-yellow-300" />
</div>
</div>
<div className="p-5 rounded-2xl bg-purple-50 border border-purple-100 flex flex-col justify-between h-32 relative overflow-hidden">
<div className="absolute right-2 top-2 opacity-10"><MessageSquare className="w-16 h-16 text-purple-600" /></div>
<span className="text-xs font-black text-purple-600 uppercase tracking-widest">Visszajelzés</span>
<div className="flex items-end justify-between">
<h3 className="text-3xl font-black text-purple-900">{orderStats.feedback}</h3>
<CheckCircle className="w-5 h-5 text-purple-300" />
</div>
</div>
</div>
</div>
{/* Active Subs */}
<div className="bg-[#0f172a] p-8 rounded-[32px] text-white flex flex-col justify-between relative overflow-hidden shadow-xl">
<div className="absolute top-0 right-0 w-32 h-32 bg-primary/20 rounded-full blur-3xl pointer-events-none"></div>
<div>
<div className="flex items-center gap-2 text-primary mb-4">
<ShieldCheck className="w-5 h-5" />
<span className="text-xs font-black uppercase tracking-widest">Aktív Előfizetések</span>
</div>
<h3 className="text-5xl font-black mb-1">{activeSubs}</h3>
<p className="text-xs text-gray-400 font-bold uppercase tracking-wide">Karbantartott oldalak</p>
</div>
<div className="mt-6 pt-6 border-t border-gray-800">
<div className="flex justify-between items-center text-xs font-bold text-gray-300">
<span>Becsült Bevétel (Havi)</span>
<span className="text-primary">{Math.round(activeSubs * (59990/12)).toLocaleString()} Ft</span>
</div>
</div>
</div>
</div>
{/* Yearly Chart */}
<div className="bg-white p-8 rounded-[32px] border border-gray-100 shadow-sm">
<div className="flex justify-between items-center mb-8">
<h4 className="text-sm font-black text-gray-900 uppercase tracking-widest flex items-center gap-2">
<TrendingUp className="w-4 h-4 text-primary" /> Rendelések alakulása ({currentYear})
</h4>
<div className="bg-gray-100 px-3 py-1 rounded-lg text-[10px] font-bold text-gray-500 uppercase">Havi bontás</div>
</div>
<div className="h-64 w-full flex items-end justify-between gap-2 sm:gap-4 px-2">
{monthlyOrders.map((count, idx) => {
const heightPercentage = maxOrderCount > 0 ? (count / maxOrderCount) * 100 : 0;
return (
<div key={idx} className="flex-1 flex flex-col items-center gap-2 group">
<div className="w-full relative flex items-end justify-center h-48 bg-gray-50 rounded-t-xl rounded-b-md overflow-hidden">
<div
className="w-full bg-primary/80 group-hover:bg-primary transition-all duration-500 rounded-t-lg relative min-h-[4px]"
style={{ height: `${heightPercentage}%` }}
>
{count > 0 && (
<div className="absolute -top-8 left-1/2 -translate-x-1/2 bg-gray-900 text-white text-[10px] font-bold px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity">
{count} db
</div>
)}
</div>
</div>
<span className="text-[10px] font-bold text-gray-400 uppercase tracking-wide group-hover:text-primary transition-colors">{monthLabels[idx]}</span>
</div>
)
})}
</div>
</div>
</div>
<div className="bg-white p-8 rounded-[32px] border border-gray-100 shadow-sm">
<p className="text-xs font-bold text-gray-400 uppercase mb-3 tracking-widest">Rendelések</p>
<h3 className="text-4xl md:text-5xl font-black text-gray-900">{orders.length}</h3>
</div>
<div className="bg-white p-8 rounded-[32px] border border-gray-100 shadow-sm">
<p className="text-xs font-bold text-gray-400 uppercase mb-3 tracking-widest">Aktív Előfizetések</p>
<h3 className="text-4xl md:text-5xl font-black text-gray-900">{subscriptions.filter(s => s.status === 'active').length}</h3>
</div>
</div>
)}
);
})()}
{activeTab === 'users' && (
<div className="bg-white rounded-[32px] border border-gray-100 shadow-sm overflow-hidden">