From 8f863153cbd194b5e0aa939dddeed1f551dec112 Mon Sep 17 00:00:00 2001 From: htom Date: Mon, 5 Jan 2026 09:37:20 +0100 Subject: [PATCH] stripe changes --- components/FeedbackModal.tsx | 58 +++-- components/Navbar.tsx | 11 +- pages/Admin.tsx | 205 +++++++++++++++--- pages/Dashboard.tsx | 25 ++- .../create-checkout-session/index.ts | 2 +- 5 files changed, 241 insertions(+), 60 deletions(-) diff --git a/components/FeedbackModal.tsx b/components/FeedbackModal.tsx index 74ef1ec..940a568 100644 --- a/components/FeedbackModal.tsx +++ b/components/FeedbackModal.tsx @@ -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 = ({ isOpen, onClose, o // Approval Flow const [approvalConfirmed, setApprovalConfirmed] = useState(false); + const [approvedDomain, setApprovedDomain] = useState(''); // Revision Flow const [designCheckboxes, setDesignCheckboxes] = useState([]); @@ -47,9 +48,10 @@ export const FeedbackModal: React.FC = ({ 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 = ({ 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 = ({ isOpen, onClose, o {mainDecision === 'approved' && ( -
-

- Megerősítés -

- +
+
+

+ Megerősítés +

+ +
+ +
+ +
+ + 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" + /> +
+

+ 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. +

+
)} diff --git a/components/Navbar.tsx b/components/Navbar.tsx index 21f73fc..f17971d 100644 --- a/components/Navbar.tsx +++ b/components/Navbar.tsx @@ -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" > - {isAdmin &&
} + {isAdmin && ( +
+ +
+ )} {isProfileOpen && ( @@ -233,4 +238,4 @@ export const Navbar: React.FC = () => { )} ); -}; \ No newline at end of file +}; diff --git a/pages/Admin.tsx b/pages/Admin.tsx index abf21f7..5e1f56e 100644 --- a/pages/Admin.tsx +++ b/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: `
MotionWeb

Kedves ${data.customer}!

-

Köszönöm a visszajelzését a ${data.package} demó verziójával kapcsolatban.

-

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.

+

Köszönöm a visszajelzéseit! Megkezdtem a kért módosítások átvezetését a weboldalon.

+

Hamarosan jelentkezem a frissített verzióval.

Üdvözlettel,
Balogh Bence Benedek
MotionWeb | motionweb.hu
` }, @@ -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 = () => {
- {activeTab === 'overview' && ( -
-
-

Látogatók

-

{visitorStats.month}

+ {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 ( +
+
+

Statisztika & Elemzés

+
+
+ + {/* Visitors Section */} +
+
+
+
+
+
+ Heti Látogatók +
+

{visitorStats.week}

+

Aktuális hét

+
+
+
+
+
+
+
+ Havi Látogatók +
+

{visitorStats.month}

+

Becsült aktivitás

+
+
+
+
+
+
+
+ Összes Látogató +
+

{visitorStats.month}

+

Indulás óta

+
+
+
+ + {/* Orders Funnel & Active Subs */} +
+ {/* Funnel */} +
+

+ Rendelési Folyamat +

+
+
+
+ Új Rendelés +
+

{orderStats.new}

+ +
+
+
+
+ Folyamatban +
+

{orderStats.inProgress}

+ +
+
+
+
+ Visszajelzés +
+

{orderStats.feedback}

+ +
+
+
+
+ + {/* Active Subs */} +
+
+
+
+ + Aktív Előfizetések +
+

{activeSubs}

+

Karbantartott oldalak

+
+
+
+ Becsült Bevétel (Havi) + {Math.round(activeSubs * (59990/12)).toLocaleString()} Ft +
+
+
+
+ + {/* Yearly Chart */} +
+
+

+ Rendelések alakulása ({currentYear}) +

+
Havi bontás
+
+ +
+ {monthlyOrders.map((count, idx) => { + const heightPercentage = maxOrderCount > 0 ? (count / maxOrderCount) * 100 : 0; + return ( +
+
+
+ {count > 0 && ( +
+ {count} db +
+ )} +
+
+ {monthLabels[idx]} +
+ ) + })} +
+
-
-

Rendelések

-

{orders.length}

-
-
-

Aktív Előfizetések

-

{subscriptions.filter(s => s.status === 'active').length}

-
-
- )} + ); + })()} {activeTab === 'users' && (
diff --git a/pages/Dashboard.tsx b/pages/Dashboard.tsx index f26b362..5509989 100644 --- a/pages/Dashboard.tsx +++ b/pages/Dashboard.tsx @@ -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({ diff --git a/supabase/functions/create-checkout-session/index.ts b/supabase/functions/create-checkout-session/index.ts index a17e216..d8bbbd1 100644 --- a/supabase/functions/create-checkout-session/index.ts +++ b/supabase/functions/create-checkout-session/index.ts @@ -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