mirror of
https://github.com/Motion-Games/MotionWebStudio.git
synced 2026-04-21 09:00:53 +02:00
stripe changes
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { X, Info, CheckCircle, AlertTriangle, MessageSquare, Calendar, ChevronDown, ChevronUp, Wallet, ArrowLeft, RefreshCw, CreditCard } from 'lucide-react';
|
||||
import { X, Info, CheckCircle, AlertTriangle, MessageSquare, Calendar, ChevronDown, ChevronUp, Wallet, ArrowLeft, RefreshCw, CreditCard, Globe } from 'lucide-react';
|
||||
import { Button } from './Button';
|
||||
|
||||
interface FeedbackModalProps {
|
||||
@@ -18,6 +18,7 @@ export const FeedbackModal: React.FC<FeedbackModalProps> = ({ isOpen, onClose, o
|
||||
|
||||
// Approval Flow
|
||||
const [approvalConfirmed, setApprovalConfirmed] = useState(false);
|
||||
const [approvedDomain, setApprovedDomain] = useState('');
|
||||
|
||||
// Revision Flow
|
||||
const [designCheckboxes, setDesignCheckboxes] = useState<string[]>([]);
|
||||
@@ -47,9 +48,10 @@ export const FeedbackModal: React.FC<FeedbackModalProps> = ({ isOpen, onClose, o
|
||||
setShowPayment(false);
|
||||
setApprovalConfirmed(false);
|
||||
setRevisionConfirmed(false);
|
||||
setApprovedDomain(order?.details?.domainName || '');
|
||||
// Reset other fields if needed
|
||||
}
|
||||
}, [isOpen]);
|
||||
}, [isOpen, order]);
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
@@ -95,7 +97,8 @@ export const FeedbackModal: React.FC<FeedbackModalProps> = ({ isOpen, onClose, o
|
||||
submittedAt: new Date().toISOString(),
|
||||
approval: mainDecision === 'approved' ? {
|
||||
confirmed: approvalConfirmed,
|
||||
paymentComplete: showPayment // Flag that payment step was shown
|
||||
paymentComplete: showPayment, // Flag that payment step was shown
|
||||
domain: approvedDomain // Pass the domain
|
||||
} : null,
|
||||
revision: isRevision ? {
|
||||
design: { selected: designCheckboxes, comment: designText },
|
||||
@@ -270,21 +273,40 @@ export const FeedbackModal: React.FC<FeedbackModalProps> = ({ isOpen, onClose, o
|
||||
</div>
|
||||
|
||||
{mainDecision === 'approved' && (
|
||||
<div className="animate-fade-in bg-green-50 p-6 rounded-2xl border-2 border-green-200 shadow-inner">
|
||||
<h3 className="text-green-900 font-black mb-4 flex items-center gap-2 uppercase text-sm tracking-widest">
|
||||
<CheckCircle className="w-5 h-5" /> Megerősítés
|
||||
</h3>
|
||||
<label className="flex items-start cursor-pointer group">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={approvalConfirmed}
|
||||
onChange={(e) => setApprovalConfirmed(e.target.checked)}
|
||||
className="mt-1 w-6 h-6 text-green-600 rounded-lg focus:ring-green-500 border-green-300"
|
||||
/>
|
||||
<span className="ml-4 text-sm text-green-800 font-bold leading-relaxed">
|
||||
Tudomásul veszem, hogy a jóváhagyással elfogadom a jelenlegi állapotot, és a folyamat a végleges elszámolással folytatódik.
|
||||
</span>
|
||||
</label>
|
||||
<div className="space-y-6">
|
||||
<div className="animate-fade-in bg-green-50 p-6 rounded-2xl border-2 border-green-200 shadow-inner">
|
||||
<h3 className="text-green-900 font-black mb-4 flex items-center gap-2 uppercase text-sm tracking-widest">
|
||||
<CheckCircle className="w-5 h-5" /> Megerősítés
|
||||
</h3>
|
||||
<label className="flex items-start cursor-pointer group">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={approvalConfirmed}
|
||||
onChange={(e) => setApprovalConfirmed(e.target.checked)}
|
||||
className="mt-1 w-6 h-6 text-green-600 rounded-lg focus:ring-green-500 border-green-300"
|
||||
/>
|
||||
<span className="ml-4 text-sm text-green-800 font-bold leading-relaxed">
|
||||
Tudomásul veszem, hogy a jóváhagyással elfogadom a jelenlegi állapotot, és a folyamat a végleges elszámolással folytatódik.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="animate-fade-in">
|
||||
<label className="block text-xs font-black text-gray-900 uppercase tracking-widest mb-2 ml-1">Végleges Domain Név</label>
|
||||
<div className="relative">
|
||||
<Globe className="absolute left-4 top-3.5 w-5 h-5 text-gray-400" />
|
||||
<input
|
||||
type="text"
|
||||
value={approvedDomain}
|
||||
onChange={(e) => setApprovedDomain(e.target.value)}
|
||||
placeholder="pl. mintaweboldal.hu"
|
||||
className="w-full pl-12 pr-4 py-3 rounded-xl border border-gray-300 bg-white text-black focus:ring-4 focus:ring-green-100 focus:border-green-500 outline-none transition-all font-bold"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-[10px] text-gray-500 mt-2 ml-1 font-medium leading-relaxed">
|
||||
Kérlek add meg, milyen domain címen szeretnéd elérni a weboldalt. Átadás előtt ellenőrizzük a foglalhatóságot/elérhetőséget, és ha probléma merül fel, felvesszük veled a kapcsolatot.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { Menu, X, Code2, User, LogIn, UserPlus, LogOut, LayoutDashboard, ShieldAlert } from 'lucide-react';
|
||||
import { Menu, X, Code2, User, LogIn, UserPlus, LogOut, LayoutDashboard, ShieldAlert, Crown } from 'lucide-react';
|
||||
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { Button } from './Button';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
@@ -114,7 +115,11 @@ export const Navbar: React.FC = () => {
|
||||
aria-label="Felhasználói fiók"
|
||||
>
|
||||
<User className="w-6 h-6" />
|
||||
{isAdmin && <div className="absolute top-1 right-1 w-2.5 h-2.5 bg-red-500 rounded-full border-2 border-white"></div>}
|
||||
{isAdmin && (
|
||||
<div className="absolute -top-1 -right-1 bg-white rounded-full p-0.5 shadow-sm border border-gray-100">
|
||||
<Crown className="w-3.5 h-3.5 text-yellow-500 fill-yellow-500" />
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{isProfileOpen && (
|
||||
@@ -233,4 +238,4 @@ export const Navbar: React.FC = () => {
|
||||
)}
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
205
pages/Admin.tsx
205
pages/Admin.tsx
@@ -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">
|
||||
|
||||
@@ -213,6 +213,18 @@ export const Dashboard: React.FC = () => {
|
||||
const paymentSummary = currentOrder.details?.payment_summary;
|
||||
const isStandardPackage = ['Landing Page', 'Pro Web'].includes(currentOrder.package);
|
||||
|
||||
// Extract the new domain if provided during approval
|
||||
const approvedDomain = feedbackData.approval?.domain;
|
||||
|
||||
// Construct base updated details
|
||||
const updatedDetails = {
|
||||
...(currentOrder.details || {}),
|
||||
latestFeedback: feedbackData,
|
||||
feedbackDate: new Date().toISOString(),
|
||||
// If approved domain is provided, update the main domainName field so it's visible in Admin
|
||||
...(approvedDomain ? { domainName: approvedDomain } : {})
|
||||
};
|
||||
|
||||
// Check if payment is needed: Approved + Standard Package + Not Custom Price + Has Remaining Balance
|
||||
// Note: paymentSummary.remaining > 0 check is implicitly handled by Logic in FeedbackModal (it shows payment button only if true)
|
||||
// But we double check here for security.
|
||||
@@ -240,12 +252,7 @@ export const Dashboard: React.FC = () => {
|
||||
|
||||
if (checkoutData?.url) {
|
||||
// Update details with feedback content BEFORE redirecting
|
||||
// This ensures we save the "Approval" state even if they drop off payment (status remains pending_feedback though)
|
||||
const updatedDetails = {
|
||||
...(currentOrder.details || {}),
|
||||
latestFeedback: feedbackData,
|
||||
feedbackDate: new Date().toISOString()
|
||||
};
|
||||
// This ensures we save the "Approval" and the new domain even if they drop off payment (status remains pending_feedback though)
|
||||
await supabase.from('orders').update({ details: updatedDetails }).eq('id', selectedOrderId);
|
||||
|
||||
// Redirect to Stripe
|
||||
@@ -257,12 +264,6 @@ export const Dashboard: React.FC = () => {
|
||||
}
|
||||
|
||||
// If no payment needed (e.g. revision request, or custom price, or enterprise), update status directly
|
||||
const updatedDetails = {
|
||||
...(currentOrder.details || {}),
|
||||
latestFeedback: feedbackData,
|
||||
feedbackDate: new Date().toISOString()
|
||||
};
|
||||
|
||||
const newStatus = 'in_progress'; // Send back to dev in both cases (to finalize or revise)
|
||||
|
||||
const { error: updateError } = await supabase.from('orders').update({
|
||||
|
||||
@@ -51,7 +51,7 @@ serve(async (req) => {
|
||||
priceId = 'price_1SiIif25dc768V7UqsfSi345'; // Pro Web - Fennmaradó
|
||||
}
|
||||
} else if (pkg === 'Maintenance' || pkg === 'Fenntartás') {
|
||||
priceId = 'price_1SiIm025dc768V7UDFMZHDox'; // Éves fenntartás
|
||||
priceId = 'price_1SiMK525dc768V7UDxZugw0Y'; // Éves fenntartás
|
||||
}
|
||||
|
||||
// 4. Validate Logic
|
||||
|
||||
Reference in New Issue
Block a user