Spaces:
Running
Running
| import React, { useState } from 'react'; | |
| import { createPortal } from 'react-dom'; | |
| import { Check, X, Loader2 } from 'lucide-react'; | |
| import { motion, AnimatePresence } from 'framer-motion'; | |
| import { apiClient } from '../../api/client'; | |
| import toast from 'react-hot-toast'; | |
| interface Props { | |
| onClose: () => void; | |
| } | |
| const PricingModal: React.FC<Props> = ({ onClose }) => { | |
| const [loadingPlan, setLoadingPlan] = useState<string | null>(null); | |
| const handleUpgrade = async (plan: string) => { | |
| try { | |
| setLoadingPlan(plan); | |
| // Mocking subscription upgrade instead of real Stripe call for now | |
| setTimeout(() => { | |
| setLoadingPlan(null); | |
| toast.success(`Zmieniono plan subskrypcji na: ${plan.toUpperCase()}`); | |
| onClose(); | |
| }, 1500); | |
| } catch (err) { | |
| console.error(err); | |
| setLoadingPlan(null); | |
| toast.error("B艂膮d zmiany planu."); | |
| } | |
| }; | |
| return createPortal( | |
| <AnimatePresence> | |
| <motion.div | |
| className="pricing-backdrop" | |
| initial={{ opacity: 0 }} | |
| animate={{ opacity: 1 }} | |
| exit={{ opacity: 0 }} | |
| style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.85)', backdropFilter: 'blur(5px)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 9999 }} | |
| > | |
| <motion.div | |
| className="glass-card pricing-modal-card" | |
| style={{ width: '1100px', maxWidth: '95%', maxHeight: '95vh', overflowY: 'auto', background: '#0B0E14', padding: '2.5rem' }} | |
| initial="hidden" animate="show" exit="hidden" | |
| variants={{ | |
| hidden: { opacity: 0, scale: 0.95, y: 20 }, | |
| show: { opacity: 1, scale: 1, y: 0, transition: { staggerChildren: 0.15, ease: "easeOut", duration: 0.4 } } | |
| }} | |
| > | |
| <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '2rem' }}> | |
| <h2>Rozszerz limity AI do maksimum</h2> | |
| <X size={24} style={{ cursor: 'pointer', color: 'var(--text-muted)' }} onClick={onClose} /> | |
| </div> | |
| <div className="pricing-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: '2rem' }}> | |
| {/* Free */} | |
| <motion.div variants={{hidden: {opacity: 0, y: 30}, show: {opacity: 1, y: 0}}} className="glass-card" style={{ border: '1px solid var(--border-subtle)', opacity: 0.8, display: 'flex', flexDirection: 'column' }}> | |
| <div style={{ color: 'var(--text-muted)', fontSize: '0.85rem', textTransform: 'uppercase', letterSpacing: '1px', fontWeight: 'bold' }}>Plan Podstawowy</div> | |
| <div style={{ fontSize: '2.5rem', fontWeight: 800, margin: '1rem 0', color: 'var(--text-primary)' }}>0 PLN<span style={{ fontSize: '1rem', color: 'var(--text-muted)'}}>/mc</span></div> | |
| <p style={{ fontSize: '0.9rem', color: 'var(--text-muted)', lineHeight: '1.4' }}>Dobre na start, by sprawdzi膰 mo偶liwo艣ci Kreatora AI.</p> | |
| <ul style={{ listStyle: 'none', padding: 0, margin: '1.5rem 0 2rem 0', display: 'flex', flexDirection: 'column', gap: '1rem', flex: 1 }}> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem' }}><Check size={18} color="var(--accent-green)" style={{flexShrink:0}}/> Ograniczone iteracje: 15 / 24h</li> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem' }}><Check size={18} color="var(--accent-green)" style={{flexShrink:0}}/> Do 100K token贸w AI / mc</li> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem', color: 'var(--text-muted)' }}><X size={18} style={{flexShrink:0}}/> Brak dedykowanych baz RAG</li> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem', color: 'var(--text-muted)' }}><X size={18} style={{flexShrink:0}}/> Tylko podgl膮d wniosk贸w</li> | |
| </ul> | |
| <button className="btn btn-secondary" style={{ width: '100%', cursor: 'not-allowed' }} disabled>Plan Aktualny</button> | |
| </motion.div> | |
| {/* Pro */} | |
| <motion.div variants={{hidden: {opacity: 0, y: 30}, show: {opacity: 1, y: 0}}} className="glass-card" style={{ border: '2px solid var(--accent-green)', position: 'relative', transform: 'scale(1.05)', zIndex: 1, boxShadow: '0 0 30px rgba(16, 185, 129, 0.15)', display: 'flex', flexDirection: 'column' }}> | |
| <div style={{ position: 'absolute', top: '-14px', background: 'linear-gradient(90deg, #10B981, #059669)', padding: '4px 16px', borderRadius: '12px', fontSize: '0.75rem', fontWeight: "bold", left: '50%', transform: 'translateX(-50%)', whiteSpace: 'nowrap', boxShadow: '0 5px 15px rgba(16,185,129,0.3)' }}>NAJLEPSZY WYB脫R</div> | |
| <div style={{ color: 'var(--accent-green)', fontSize: '0.85rem', textTransform: 'uppercase', letterSpacing: '1px', fontWeight: 'bold' }}>Pro</div> | |
| <div style={{ fontSize: '3rem', fontWeight: 800, margin: '1rem 0', color: '#fff' }}>99 PLN<span style={{ fontSize: '1.2rem', color: 'var(--text-muted)'}}>/mc</span></div> | |
| <p style={{ fontSize: '0.9rem', color: 'rgba(255,255,255,0.8)', lineHeight: '1.4' }}>Idealny dla firm doradczych optymalizuj膮cych czas pracy.</p> | |
| <ul style={{ listStyle: 'none', padding: 0, margin: '1.5rem 0 2rem 0', display: 'flex', flexDirection: 'column', gap: '1rem', flex: 1 }}> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem', fontWeight: 600 }}><Check size={18} color="var(--accent-green)" style={{flexShrink:0}}/> Bezpieczne, 50 iteracji / 24h</li> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem', fontWeight: 600 }}><Check size={18} color="var(--accent-green)" style={{flexShrink:0}}/> Mocne 500K token贸w AI / mc</li> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem', fontWeight: 600 }}><Check size={18} color="var(--accent-green)" style={{flexShrink:0}}/> Eksporty gotowych um贸w DOCX / PDF</li> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem' }}><Check size={18} color="var(--accent-green)" style={{flexShrink:0}}/> Priorytetowe wsparcie Critic'a</li> | |
| </ul> | |
| <motion.button | |
| whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} | |
| className="btn btn-primary" | |
| style={{ width: '100%', background: 'linear-gradient(90deg, #10B981, #059669)', fontSize: '1.1rem', fontWeight: 800, padding: '1rem', boxShadow: '0 5px 15px rgba(16,185,129,0.3)', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '0.5rem' }} | |
| onClick={() => handleUpgrade('pro')} | |
| disabled={loadingPlan !== null} | |
| > | |
| {loadingPlan === 'pro' && <Loader2 className="spinner" size={20} style={{ animation: 'spin 1s linear infinite' }} />} | |
| Przejd藕 na Pro | |
| </motion.button> | |
| </motion.div> | |
| {/* Business */} | |
| <motion.div variants={{hidden: {opacity: 0, y: 30}, show: {opacity: 1, y: 0}}} className="glass-card" style={{ border: '1px solid var(--accent-blue)', display: 'flex', flexDirection: 'column' }}> | |
| <div style={{ color: 'var(--accent-blue)', fontSize: '0.85rem', textTransform: 'uppercase', letterSpacing: '1px', fontWeight: 'bold' }}>Business Enterprise</div> | |
| <div style={{ fontSize: '2.5rem', fontWeight: 800, margin: '1rem 0', color: 'var(--text-primary)' }}>299 PLN<span style={{ fontSize: '1rem', color: 'var(--text-muted)'}}>/mc</span></div> | |
| <p style={{ fontSize: '0.9rem', color: 'var(--text-muted)', lineHeight: '1.4' }}>Rozwi膮zanie bezkompromisowe dla dzia艂贸w R&D.</p> | |
| <ul style={{ listStyle: 'none', padding: 0, margin: '1.5rem 0 2rem 0', display: 'flex', flexDirection: 'column', gap: '1rem', flex: 1 }}> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem' }}><Check size={18} color="var(--accent-blue)" style={{flexShrink:0}}/> Nielimitowane Iteracje</li> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem' }}><Check size={18} color="var(--accent-blue)" style={{flexShrink:0}}/> Do 2M+ Token贸w AI / 30 dni</li> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem' }}><Check size={18} color="var(--accent-blue)" style={{flexShrink:0}}/> Customowe RAG i wektoryzacja bazy</li> | |
| <li style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-start', fontSize: '0.9rem' }}><Check size={18} color="var(--accent-blue)" style={{flexShrink:0}}/> Personalizowany Expert-AI</li> | |
| </ul> | |
| <motion.button | |
| whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} | |
| className="btn btn-secondary" | |
| style={{ width: '100%', color: 'var(--accent-blue)', borderColor: 'rgba(59, 130, 246, 0.4)', background: 'rgba(59, 130, 246, 0.05)', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '0.5rem' }} | |
| onClick={() => handleUpgrade('business')} | |
| disabled={loadingPlan !== null} | |
| > | |
| {loadingPlan === 'business' && <Loader2 className="spinner" size={20} style={{ animation: 'spin 1s linear infinite' }} />} | |
| Kontakt z Sales | |
| </motion.button> | |
| </motion.div> | |
| </div> | |
| </motion.div> | |
| </motion.div> | |
| </AnimatePresence>, | |
| document.body | |
| ); | |
| }; | |
| export default PricingModal; | |