Spaces:
Running
Running
| import React, { useState } from 'react'; | |
| import { Building2, FileText, Settings, Plus, Sparkles, TrendingUp, Shield } from 'lucide-react'; | |
| import UsageCard from './UsageCard'; | |
| import PricingModal from './PricingModal'; | |
| import WizardModal from './WizardModal'; | |
| import { NavLink, useLocation } from 'react-router-dom'; | |
| import { UserButton, useUser } from '@clerk/clerk-react'; | |
| import { useMe } from '../../hooks/useMe'; | |
| const Sidebar: React.FC = () => { | |
| const [showPricing, setShowPricing] = useState(false); | |
| const [showWizard, setShowWizard] = useState(false); | |
| const location = useLocation(); | |
| const { user } = useUser(); | |
| const { data: me } = useMe(); | |
| const isProjectWorkspace = location.pathname.startsWith('/projects/'); | |
| // tier hierarchy: me (DB) > Clerk metadata > 'free' | |
| const tier = me?.tier ?? (user?.publicMetadata?.stripe_subscription as string) ?? 'free'; | |
| const isPro = tier === 'pro' || tier === 'business'; | |
| const tierLabel = tier.toUpperCase(); | |
| const tierColor = tier === 'business' ? '#f59e0b' : tier === 'pro' ? 'var(--accent-green)' : '#6b7280'; | |
| return ( | |
| <> | |
| <div className="sidebar-header"> | |
| <div className="sidebar-logo" style={{ background: 'linear-gradient(135deg, var(--accent-green), var(--accent-blue))', color: '#000' }}>GF</div> | |
| <div> | |
| <h2 style={{ fontSize: '1.2rem', fontWeight: 800, color: 'var(--text-primary)' }}>GrantForge</h2> | |
| <p style={{ fontSize: '0.8rem', color: 'var(--accent-green)', fontWeight: 'bold' }}>Enterprise <span style={{color:'var(--text-muted)'}}>v2.0</span></p> | |
| </div> | |
| </div> | |
| <div className="sidebar-content sidebar-menu"> | |
| <UsageCard onUpgradeClick={() => setShowPricing(true)} compact={isProjectWorkspace} /> | |
| <div className="glass-card user-profile-menu" style={{ padding: isProjectWorkspace ? '1rem' : '1.8rem' }}> | |
| <div className="card-title"> | |
| Profil Doradcy | |
| <Settings size={14} style={{ cursor: 'pointer' }} /> | |
| </div> | |
| <div style={{ display: 'flex', alignItems: 'center', gap: '1rem', marginTop: '1rem' }}> | |
| <UserButton afterSignOutUrl="/" appearance={{ elements: { avatarBox: { width: '45px', height: '45px' } } }} /> | |
| <div style={{ flex: 1, minWidth: 0 }}> | |
| <h3 style={{ fontSize: '1rem', margin: '0 0 0.3rem 0', color: 'var(--text-primary)', overflow: 'hidden', wordWrap: 'break-word', whiteSpace: 'normal', lineHeight: '1.4' }}> | |
| {user ? `${user.firstName || ''} ${user.lastName || ''}`.trim() || user.primaryEmailAddress?.emailAddress : 'Zaloguj się'} | |
| </h3> | |
| <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}> | |
| <span style={{ | |
| color: tierColor, | |
| fontSize: '0.7rem', | |
| fontWeight: 700, | |
| textTransform: 'uppercase', | |
| letterSpacing: '0.08em', | |
| background: `${tierColor}18`, | |
| border: `1px solid ${tierColor}40`, | |
| padding: '0.15rem 0.5rem', | |
| borderRadius: '4px', | |
| display: 'flex', | |
| alignItems: 'center', | |
| gap: '0.3rem', | |
| }} | |
| > | |
| {isPro && <span style={{ width: '6px', height: '6px', borderRadius: '50%', background: tierColor, display: 'inline-block', boxShadow: `0 0 8px ${tierColor}` }} />} | |
| {tierLabel} | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem', marginTop: '1rem' }}> | |
| <div className="card-title" style={{ marginTop: '1rem' }}>Akcje i Nawigacja</div> | |
| <button | |
| className="btn hover-lift new-project-btn tour-step-new-project" | |
| style={{ | |
| width: '100%', | |
| background: 'linear-gradient(90deg, var(--accent-green), #3b82f6)', | |
| boxShadow: '0 0 20px rgba(16,185,129,0.3)', | |
| border: 'none', | |
| color: '#000', | |
| fontWeight: 800, | |
| padding: '1rem', | |
| display: 'flex', | |
| alignItems: 'center', | |
| justifyContent: 'center', | |
| gap: '0.8rem', | |
| marginBottom: '1rem' | |
| }} | |
| onClick={() => setShowWizard(true)} | |
| > | |
| <Plus size={18} /> Nowy Projekt Dotacyjny | |
| </button> | |
| <NavLink to="/projects" className={({isActive}) => `btn projects-list ${isActive ? 'btn-secondary' : ''}`} style={({isActive}) => ({ justifyContent: 'flex-start', background: 'transparent', border: 'none', color: isActive ? '#fff' : 'var(--text-secondary)' })}> | |
| <FileText size={16} /> Moje Projekty | |
| </NavLink> | |
| <NavLink to="/nabory" className={({isActive}) => `btn ${isActive ? 'btn-secondary' : ''}`} style={({isActive}) => ({ justifyContent: 'flex-start', background: 'transparent', border: 'none', color: isActive ? '#fff' : 'var(--text-secondary)' })}> | |
| <TrendingUp size={16} /> Aktywne Nabory | |
| </NavLink> | |
| <NavLink to="/about" className={({isActive}) => `btn ${isActive ? 'btn-secondary' : ''}`} style={({isActive}) => ({ justifyContent: 'flex-start', background: 'transparent', border: 'none', color: isActive ? '#fff' : 'var(--text-secondary)' })}> | |
| <Sparkles size={16} /> O Programie | |
| </NavLink> | |
| <NavLink to="/help" className={({isActive}) => `btn ${isActive ? 'btn-secondary' : ''}`} style={({isActive}) => ({ justifyContent: 'flex-start', background: 'transparent', border: 'none', color: isActive ? '#fff' : 'var(--text-secondary)' })}> | |
| <Building2 size={16} /> Pomoc | |
| </NavLink> | |
| <NavLink to="/settings" className={({isActive}) => `btn ${isActive ? 'btn-secondary' : ''}`} style={({isActive}) => ({ justifyContent: 'flex-start', background: 'transparent', border: 'none', color: isActive ? '#fff' : 'var(--text-secondary)' })}> | |
| <Settings size={16} /> Ustawienia | |
| </NavLink> | |
| <NavLink to="/admin" className={({isActive}) => `btn ${isActive ? 'btn-secondary' : ''}`} style={({isActive}) => ({ justifyContent: 'flex-start', background: 'transparent', border: 'none', color: isActive ? '#f59e0b' : 'var(--text-secondary)' })}> | |
| <Shield size={16} /> Admin Panel | |
| </NavLink> | |
| <NavLink to="/beta" className={({isActive}) => `btn ${isActive ? 'btn-secondary' : ''}`} style={({isActive}) => ({ justifyContent: 'flex-start', background: 'transparent', border: 'none', color: isActive ? '#10b981' : 'var(--text-secondary)' })}> | |
| <Sparkles size={16} /> Beta Guide | |
| </NavLink> | |
| </div> | |
| </div> | |
| {showPricing && <PricingModal onClose={() => setShowPricing(false)} />} | |
| {showWizard && <WizardModal onClose={() => setShowWizard(false)} />} | |
| </> | |
| ); | |
| }; | |
| export default Sidebar; | |