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/RedactionEditor.tsx
import React, { useState, useEffect } from 'react';
import { Eye, EyeOff, Brain, Sparkles, Loader2, Save, X, ShieldAlert } from 'lucide-react';
import { SensitiveEntity, Language } from '../types';
import { identifySensitiveEntities } from '../geminiService';
import { translations } from '../translations';

interface RedactionEditorProps {
  text: string;
  lang: Language;
  onApply: (redactedText: string) => void;
  onClose: () => void;
}

const RedactionEditor: React.FC<RedactionEditorProps> = ({ text, lang, onApply, onClose }) => {
  const t = translations[lang];
  const [entities, setEntities] = useState<SensitiveEntity[]>([]);
  const [isAnalyzing, setIsAnalyzing] = useState(false);

  useEffect(() => {
    analyzeText();
  }, []);

  const analyzeText = async () => {
    setIsAnalyzing(true);
    const suggested = await identifySensitiveEntities(text, lang);
    setEntities(suggested);
    setIsAnalyzing(false);
  };

  const toggleRedaction = (index: number) => {
    const newEntities = [...entities];
    newEntities[index].isRedacted = !newEntities[index].isRedacted;
    setEntities(newEntities);
  };

  const applyRedaction = () => {
    let resultText = text;
    entities.forEach(entity => {
      if (entity.isRedacted) {
        // Escaping for regex
        const escaped = entity.text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        const regex = new RegExp(escaped, 'g');
        resultText = resultText.replace(regex, `[${t.redactedLabel}]`);
      }
    });
    onApply(resultText);
  };

  return (
    <div className="fixed inset-0 z-[100] flex items-center justify-center bg-slate-900/60 backdrop-blur-md p-6">
      <div className="bg-white w-full max-w-2xl rounded-[3rem] shadow-2xl overflow-hidden animate-in zoom-in duration-300 flex flex-col max-h-[90vh]">
        <div className="bg-indigo-600 p-8 text-white flex justify-between items-center">
          <div className="flex items-center gap-4">
             <div className="bg-white/20 p-2.5 rounded-2xl"><Brain size={24} /></div>
             <div>
               <h3 className="text-2xl font-black uppercase tracking-tight">{t.redactionTitle}</h3>
               <p className="text-[10px] text-indigo-200 font-bold uppercase tracking-[0.2em]">{t.redactionDesc}</p>
             </div>
          </div>
          <button onClick={onClose} className="hover:rotate-90 transition-transform"><X size={24} /></button>
        </div>

        <div className="flex-1 overflow-y-auto p-10 space-y-8">
          <div className="bg-slate-50 p-6 rounded-3xl border border-slate-100 shadow-inner">
             <p className="text-xs text-slate-600 leading-relaxed italic">"{text}"</p>
          </div>

          <div className="space-y-4">
             <div className="flex items-center justify-between">
                <h4 className="text-xs font-black text-slate-400 uppercase tracking-widest flex items-center gap-2">
                  <Sparkles size={14} /> SUGGERIMENTI AI
                </h4>
                {isAnalyzing && <Loader2 size={16} className="animate-spin text-indigo-600" />}
             </div>

             {entities.length === 0 && !isAnalyzing && (
               <div className="bg-slate-50 p-8 text-center rounded-3xl border border-dashed border-slate-200">
                  <ShieldAlert size={32} className="mx-auto text-slate-200 mb-2" />
                  <p className="text-xs font-bold text-slate-400 uppercase">Nessun dato sensibile identificato automaticamente.</p>
               </div>
             )}

             <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
               {entities.map((entity, i) => (
                 <button 
                  key={i} 
                  onClick={() => toggleRedaction(i)}
                  className={`flex items-center justify-between p-4 rounded-2xl border transition-all ${entity.isRedacted ? 'bg-indigo-50 border-indigo-200 shadow-inner' : 'bg-white border-slate-100 shadow-sm hover:border-indigo-100'}`}
                 >
                   <div className="flex flex-col items-start min-w-0">
                      <span className="text-[8px] font-black text-indigo-400 uppercase tracking-widest mb-1">{entity.type}</span>
                      <span className={`text-xs font-bold truncate w-full ${entity.isRedacted ? 'line-through text-indigo-900' : 'text-slate-700'}`}>{entity.text}</span>
                   </div>
                   {entity.isRedacted ? <EyeOff size={18} className="text-indigo-600" /> : <Eye size={18} className="text-slate-300" />}
                 </button>
               ))}
             </div>
          </div>
        </div>

        <div className="p-8 bg-slate-50 border-t border-slate-100 flex gap-4">
           <button onClick={onClose} className="flex-1 py-4 bg-white border border-slate-200 text-slate-500 rounded-2xl font-black text-[10px] uppercase tracking-widest">Annulla</button>
           <button onClick={applyRedaction} className="flex-1 py-4 bg-indigo-600 text-white rounded-2xl font-black text-[10px] uppercase tracking-widest shadow-lg shadow-indigo-100 flex items-center justify-center gap-2">
             <Save size={18} /> Applica Redazione
           </button>
        </div>
      </div>
    </div>
  );
};

export default RedactionEditor;

Youez - 2016 - github.com/yon3zu
LinuXploit