Spaces:
Running
Running
| import React, { useState, useEffect } from 'react'; | |
| import { motion } from 'framer-motion'; | |
| import { Building2, Save, CheckCircle, AlertCircle, RefreshCw, Briefcase } from 'lucide-react'; | |
| import toast from 'react-hot-toast'; | |
| import { getCompanyProfile, updateCompanyProfile, CompanyProfileData } from '../api/client'; | |
| import { SkeletonLoader } from '../components/common/SkeletonLoader'; | |
| const CompanyProfile: React.FC = () => { | |
| const [profile, setProfile] = useState<CompanyProfileData>({ | |
| nip: '', | |
| name: '', | |
| pkd_codes: [], | |
| company_size: 'mikro', | |
| location: '', | |
| description: '' | |
| }); | |
| const [loading, setLoading] = useState(true); | |
| const [saving, setSaving] = useState(false); | |
| const [pkdInput, setPkdInput] = useState(''); | |
| useEffect(() => { | |
| fetchProfile(); | |
| }, []); | |
| const fetchProfile = async () => { | |
| setLoading(true); | |
| try { | |
| const data = await getCompanyProfile(); | |
| setProfile({ | |
| nip: data.nip || '', | |
| name: data.name || '', | |
| pkd_codes: data.pkd_codes || [], | |
| company_size: data.company_size || 'mikro', | |
| location: data.location || '', | |
| description: data.description || '', | |
| is_verified: data.is_verified || false | |
| }); | |
| setPkdInput((data.pkd_codes || []).join(', ')); | |
| } catch (error) { | |
| console.error("Błąd ładowania profilu", error); | |
| toast.error("Nie udało się załadować danych firmy"); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| const handleSave = async (e: React.FormEvent) => { | |
| e.preventDefault(); | |
| if (!profile.nip) { | |
| toast.error("NIP jest wymagany"); | |
| return; | |
| } | |
| setSaving(true); | |
| try { | |
| // Przetwarzanie PKD | |
| const pkds = pkdInput.split(',') | |
| .map(p => p.trim()) | |
| .filter(p => p.length > 0); | |
| const updatedProfile = await updateCompanyProfile({ | |
| ...profile, | |
| pkd_codes: pkds | |
| }); | |
| setProfile(updatedProfile); | |
| setPkdInput((updatedProfile.pkd_codes || []).join(', ')); | |
| toast.success("Zapisano profil firmy"); | |
| } catch (error) { | |
| console.error("Błąd zapisywania", error); | |
| toast.error("Nie udało się zapisać profilu"); | |
| } finally { | |
| setSaving(false); | |
| } | |
| }; | |
| if (loading) { | |
| return ( | |
| <div style={{ padding: '2rem 3rem', maxWidth: '1000px', margin: '0 auto', width: '100%' }}> | |
| <SkeletonLoader count={1} height="80px" style={{ marginBottom: '2rem' }} /> | |
| <SkeletonLoader count={4} height="60px" style={{ marginBottom: '1rem' }} /> | |
| <SkeletonLoader count={1} height="120px" /> | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <div style={{ padding: '2rem 3rem', maxWidth: '1000px', margin: '0 auto', width: '100%', height: '100%', overflowY: 'auto' }}> | |
| <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '3rem' }}> | |
| <div> | |
| <h1 className="display-font" style={{ fontSize: '2.5rem', color: 'var(--text-primary)', marginBottom: '0.5rem', display: 'flex', alignItems: 'center', gap: '0.8rem' }}> | |
| <Building2 size={36} color="var(--accent-blue)" /> | |
| Mój Profil Firmy | |
| </h1> | |
| <p style={{ color: 'var(--text-secondary)', fontSize: '1.05rem', marginLeft: '3.4rem' }}> | |
| Zapisz dane swojego przedsiębiorstwa, aby automatycznie dopasowywać naboru i generować precyzyjniejsze wnioski. | |
| </p> | |
| </div> | |
| </div> | |
| <motion.div | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| className="glass-card" | |
| style={{ padding: '2.5rem' }} | |
| > | |
| {profile.is_verified ? ( | |
| <div style={{ background: 'rgba(16, 185, 129, 0.1)', border: '1px solid rgba(16, 185, 129, 0.3)', padding: '1rem', borderRadius: '8px', marginBottom: '2rem', display: 'flex', alignItems: 'center', gap: '0.8rem', color: 'var(--accent-green)' }}> | |
| <CheckCircle size={20} /> | |
| <div> | |
| <strong>Dane firmy zweryfikowane</strong> | |
| <p style={{ margin: 0, fontSize: '0.9rem', color: 'var(--text-secondary)' }}>Status MŚP dla tego numeru NIP został automatycznie potwierdzony.</p> | |
| </div> | |
| </div> | |
| ) : profile.nip ? ( | |
| <div style={{ background: 'rgba(239, 68, 68, 0.1)', border: '1px solid rgba(239, 68, 68, 0.3)', padding: '1rem', borderRadius: '8px', marginBottom: '2rem', display: 'flex', alignItems: 'center', gap: '0.8rem', color: '#ef4444' }}> | |
| <AlertCircle size={20} /> | |
| <div> | |
| <strong>Brak weryfikacji statusu MŚP</strong> | |
| <p style={{ margin: 0, fontSize: '0.9rem', color: 'var(--text-secondary)' }}>Zapisz poprawne dane, aby system dokonał walidacji w KRS/CEIDG.</p> | |
| </div> | |
| </div> | |
| ) : null} | |
| <form onSubmit={handleSave} style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem' }}> | |
| <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.5rem' }}> | |
| <div> | |
| <label style={{ display: 'block', color: 'var(--text-secondary)', marginBottom: '0.5rem', fontWeight: 600 }}>Numer NIP *</label> | |
| <input | |
| type="text" | |
| value={profile.nip} | |
| onChange={(e) => setProfile({...profile, nip: e.target.value})} | |
| placeholder="Np. 5213214567" | |
| required | |
| style={{ width: '100%', padding: '1rem', background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff' }} | |
| /> | |
| </div> | |
| <div> | |
| <label style={{ display: 'block', color: 'var(--text-secondary)', marginBottom: '0.5rem', fontWeight: 600 }}>Nazwa Firmy</label> | |
| <input | |
| type="text" | |
| value={profile.name || ''} | |
| onChange={(e) => setProfile({...profile, name: e.target.value})} | |
| placeholder="Pełna nazwa przedsiębiorstwa" | |
| style={{ width: '100%', padding: '1rem', background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff' }} | |
| /> | |
| </div> | |
| </div> | |
| <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.5rem' }}> | |
| <div> | |
| <label style={{ display: 'block', color: 'var(--text-secondary)', marginBottom: '0.5rem', fontWeight: 600 }}>Status Przedsiębiorstwa (MŚP)</label> | |
| <select | |
| value={profile.company_size || 'mikro'} | |
| onChange={(e) => setProfile({...profile, company_size: e.target.value})} | |
| style={{ width: '100%', padding: '1rem', background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff', outline: 'none' }} | |
| > | |
| <option value="mikro" style={{ background: '#0B0E14' }}>Mikroprzedsiębiorstwo</option> | |
| <option value="mala" style={{ background: '#0B0E14' }}>Małe przedsiębiorstwo</option> | |
| <option value="srednia" style={{ background: '#0B0E14' }}>Średnie przedsiębiorstwo</option> | |
| <option value="duza" style={{ background: '#0B0E14' }}>Duże przedsiębiorstwo (Small Mid-caps/Mid-caps)</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label style={{ display: 'block', color: 'var(--text-secondary)', marginBottom: '0.5rem', fontWeight: 600 }}>Kody PKD (po przecinku)</label> | |
| <div style={{ position: 'relative' }}> | |
| <Briefcase size={18} color="var(--text-muted)" style={{ position: 'absolute', top: '50%', transform: 'translateY(-50%)', left: '1rem' }} /> | |
| <input | |
| type="text" | |
| value={pkdInput} | |
| onChange={(e) => setPkdInput(e.target.value)} | |
| placeholder="Np. 62.01.Z, 72.19.Z" | |
| style={{ width: '100%', padding: '1rem 1rem 1rem 3rem', background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff' }} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <label style={{ display: 'block', color: 'var(--text-secondary)', marginBottom: '0.5rem', fontWeight: 600 }}>Lokalizacja (Województwo)</label> | |
| <input | |
| type="text" | |
| value={profile.location || ''} | |
| onChange={(e) => setProfile({...profile, location: e.target.value})} | |
| placeholder="Np. mazowieckie" | |
| style={{ width: '100%', padding: '1rem', background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff' }} | |
| /> | |
| </div> | |
| <div> | |
| <label style={{ display: 'block', color: 'var(--text-secondary)', marginBottom: '0.5rem', fontWeight: 600 }}>Opis Działalności (Krótki profil technologiczny / obszar innowacji)</label> | |
| <textarea | |
| value={profile.description || ''} | |
| onChange={(e) => setProfile({...profile, description: e.target.value})} | |
| placeholder="Czym zajmuje się firma? Jakie innowacje wprowadza? Ten opis pomoże w automatycznym generowaniu sekcji." | |
| style={{ width: '100%', padding: '1rem', background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff', minHeight: '120px', resize: 'vertical' }} | |
| /> | |
| </div> | |
| <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '1rem' }}> | |
| <button | |
| type="submit" | |
| disabled={saving} | |
| className="btn btn-primary" | |
| style={{ padding: '1rem 2rem', fontSize: '1.05rem', background: 'var(--accent-blue)', display: 'flex', alignItems: 'center', gap: '0.5rem', border: 'none', color: '#fff', fontWeight: 600 }} | |
| > | |
| {saving ? <RefreshCw size={20} className="spin" /> : <Save size={20} />} | |
| {saving ? 'Zapisywanie...' : 'Zapisz Profil Firmy'} | |
| </button> | |
| </div> | |
| </form> | |
| </motion.div> | |
| </div> | |
| ); | |
| }; | |
| export default CompanyProfile; | |