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/UserProfile.tsx
import React, { useState } from 'react';
import { User, Mail, Wallet, ShieldAlert, UserCheck, Building2, Phone, MapPin, Save, IdCard } from 'lucide-react';
import { Language } from '../types';

interface UserProfileProps {
  user: any;
  lang: Language;
  onUpdateUser?: (user: any) => void;
  clientToken?: string | null;
}

const splitName = (value: string) => {
  const parts = String(value || '').trim().split(/\s+/).filter(Boolean);
  return {
    nome: parts[0] || '',
    cognome: parts.slice(1).join(' ') || ''
  };
};

const UserProfile: React.FC<UserProfileProps> = ({ user, lang, onUpdateUser, clientToken }) => {
  const isIt = lang === 'it';
  const verified = Boolean(user?.identity?.verified);

  let saved: any = {};
  try {
    saved = JSON.parse(localStorage.getItem('ccp_profile_postal') || '{}');
  } catch (_) {
    saved = {};
  }

  const nameParts = splitName(user?.name || '');

  const [form, setForm] = useState({
    ragione_sociale: saved.ragione_sociale || user?.identity?.postal?.ragione_sociale || '',
    nome: saved.nome || user?.identity?.postal?.nome || nameParts.nome || '',
    cognome: saved.cognome || user?.identity?.postal?.cognome || nameParts.cognome || '',
    email: saved.email || user?.identity?.postal?.email || user?.email || '',
    telefono: saved.telefono || user?.identity?.postal?.telefono || '',
    codice_fiscale: saved.codice_fiscale || user?.identity?.postal?.codice_fiscale || '',
    partita_iva: saved.partita_iva || user?.identity?.postal?.partita_iva || '',
    dug: saved.dug || user?.identity?.postal?.dug || 'via',
    indirizzo: saved.indirizzo || user?.identity?.postal?.indirizzo || '',
    civico: saved.civico || user?.identity?.postal?.civico || '',
    comune: saved.comune || user?.identity?.postal?.comune || '',
    cap: saved.cap || user?.identity?.postal?.cap || '',
    provincia: saved.provincia || user?.identity?.postal?.provincia || '',
    nazione: saved.nazione || user?.identity?.postal?.nazione || 'IT'
  });

  const update = (key: string, value: string) => {
    let next = value;

    if (key === 'provincia' || key === 'nazione') {
      next = value.toUpperCase().replace(/[^A-Z]/g, '').slice(0, 2);
    }

    if (key === 'cap') {
      next = value.replace(/\D/g, '').slice(0, 5);
    }

    setForm(prev => ({ ...prev, [key]: next }));
  };

  const saveProfile = async () => {
    try {
      const postal = { ...form };

      localStorage.setItem('ccp_profile_postal', JSON.stringify(postal));

      let backendUser: any = null;

      if (clientToken) {
        const res = await fetch('/api/ai/client/profile', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'X-CCP-Token': clientToken
          },
          body: JSON.stringify({ postal })
        });

        const data = await res.json().catch(() => null);

        if (!res.ok || !data?.ok) {
          throw new Error(data?.error || 'profile_save_failed');
        }

        backendUser = data.user || null;

        if (data.postal) {
          localStorage.setItem('ccp_profile_postal', JSON.stringify(data.postal));
        }
      }

      const displayName = [postal.nome, postal.cognome].filter(Boolean).join(' ') || user?.name || 'User';

      const nextUser = {
        ...user,
        ...(backendUser || {}),
        name: backendUser?.name || displayName,
        username: backendUser?.name || displayName,
        email: user?.email,
        identity: {
          ...(user?.identity || {}),
          postal: backendUser?.postal_profile || backendUser?.profile?.postal || postal
        }
      };

      if (onUpdateUser) onUpdateUser(nextUser);
      alert(isIt ? 'Profilo salvato.' : 'Profile saved.');
    } catch (e: any) {
      alert((isIt ? 'Errore salvataggio profilo: ' : 'Profile save error: ') + (e?.message || 'unknown_error'));
    }
  };

  return (
    <div className="space-y-8">
      <div>
        <h2 className="text-5xl font-black text-slate-900 uppercase tracking-tight leading-none">
          {isIt ? 'PROFILO UTENTE' : 'USER PROFILE'}
        </h2>
        <p className="text-slate-500 font-medium text-sm mt-3">
          {isIt ? 'Dati account, azienda e indirizzo per invii documentali' : 'Account, company and postal data'}
        </p>
      </div>

      <div className="grid grid-cols-1 xl:grid-cols-2 gap-8">
        <div className="bg-white rounded-[2.5rem] border border-slate-100 shadow-sm overflow-hidden">
          <div className="h-40 bg-slate-950" />
          <div className="-mt-14 px-8 pb-8">
            <div className="w-40 h-40 rounded-[2rem] bg-slate-100 border-4 border-white flex items-center justify-center text-slate-400 shadow-sm mx-auto">
              <User size={64} />
            </div>

            <div className="text-center mt-6">
              <h3 className="text-3xl font-black text-slate-900 uppercase tracking-tight">
                {String(user?.name || 'User')}
              </h3>
              <p className="text-blue-600 font-black uppercase tracking-widest text-sm mt-2">
                {isIt ? 'Client account' : 'Client account'}
              </p>
            </div>
          </div>
        </div>

        <div className="bg-white rounded-[2.5rem] border border-slate-100 shadow-sm overflow-hidden">
          <div className="px-8 py-8 border-b border-slate-100 flex items-start gap-4">
            <div className={`w-16 h-16 rounded-[1.5rem] flex items-center justify-center ${verified ? 'bg-emerald-50 text-emerald-600' : 'bg-orange-50 text-orange-500'}`}>
              {verified ? <UserCheck size={30} /> : <ShieldAlert size={30} />}
            </div>
            <div>
              <h3 className="text-2xl font-black text-slate-900 uppercase tracking-tight">
                {isIt ? 'Informazioni account' : 'Account information'}
              </h3>
              <p className={`font-black uppercase tracking-widest text-sm mt-2 ${verified ? 'text-emerald-600' : 'text-orange-500'}`}>
                {verified ? (isIt ? 'Identità verificata' : 'Identity verified') : (isIt ? 'Identità non verificata' : 'Identity not verified')}
              </p>
            </div>
          </div>

          <div className="px-8 py-8 space-y-6">
            <InfoRow icon={<User size={20} />} label={isIt ? 'Nome profilo' : 'Profile name'} value={String(user?.name || '-')} />
            <InfoRow icon={<Mail size={20} />} label="Email" value={String(user?.email || '-')} />
            <InfoRow icon={<Wallet size={20} />} label="ABO Wallet" value={`${Number(user?.credits?.balance || 0)} ${isIt ? 'coin' : 'coins'}`} />

            <div className="rounded-[2rem] bg-slate-50 border border-slate-100 p-5">
              <p className="text-[10px] font-black uppercase tracking-widest text-slate-400">
                {isIt ? 'Ruolo accesso' : 'Access role'}
              </p>
              <p className="text-lg font-black text-slate-900 mt-1">
                {isIt ? 'Cliente' : 'Client'}
              </p>
            </div>
          </div>
        </div>
      </div>

      <div className="bg-white rounded-[2.5rem] border border-slate-100 shadow-sm overflow-hidden">
        <div className="px-8 py-8 border-b border-slate-100 flex items-start gap-4">
          <div className="w-16 h-16 rounded-[1.5rem] bg-blue-50 text-blue-600 flex items-center justify-center">
            <Building2 size={30} />
          </div>
          <div>
            <h3 className="text-2xl font-black text-slate-900 uppercase tracking-tight">
              {isIt ? 'Dati cliente e mittente' : 'Client and sender data'}
            </h3>
            <p className="text-slate-500 font-bold text-sm mt-2">
              {isIt ? 'Questi dati saranno usati per invio documenti, raccomandate e comunicazioni tracciate. L’email di accesso non viene modificata da questa sezione.' : 'These data will be used for document delivery and tracked mail. The login email is not changed here.'}
            </p>
          </div>
        </div>

        <div className="p-8 grid grid-cols-1 md:grid-cols-2 gap-5">
          <Field label="Azienda / Organizzazione" value={form.ragione_sociale} onChange={v => update('ragione_sociale', v)} placeholder="Es. CopyrightChain, LampoVert, Studio Rossi" />
          <Field label="Email per invii/ricevute" value={form.email} onChange={v => update('email', v)} placeholder="email@dominio.it" icon={<Mail size={16} />} />
          <Field label="Nome" value={form.nome} onChange={v => update('nome', v)} placeholder="Es. Marcello" />
          <Field label="Cognome" value={form.cognome} onChange={v => update('cognome', v)} placeholder="Es. Orsini" />
          <Field label="Telefono" value={form.telefono} onChange={v => update('telefono', v)} placeholder="+39 ..." icon={<Phone size={16} />} />
          <Field label="Codice fiscale" value={form.codice_fiscale} onChange={v => update('codice_fiscale', v.toUpperCase())} placeholder="Codice fiscale" icon={<IdCard size={16} />} />
          <Field label="Partita IVA" value={form.partita_iva} onChange={v => update('partita_iva', v)} placeholder="Partita IVA" />
          <Field label="Tipo strada" value={form.dug} onChange={v => update('dug', v)} placeholder="via, viale, piazza, corso" />
          <Field label="Nome strada" value={form.indirizzo} onChange={v => update('indirizzo', v)} placeholder="Es. degli Armeni" icon={<MapPin size={16} />} />
          <Field label="Numero civico" value={form.civico} onChange={v => update('civico', v)} placeholder="Es. 14" />
          <Field label="Comune / città" value={form.comune} onChange={v => update('comune', v)} placeholder="Es. Pistoia" />
          <Field label="CAP" value={form.cap} onChange={v => update('cap', v)} placeholder="51100" maxLength={5} />
          <Field label="Provincia" value={form.provincia} onChange={v => update('provincia', v)} placeholder="PT" maxLength={2} />
          <Field label="Nazione" value={form.nazione} onChange={v => update('nazione', v)} placeholder="IT" maxLength={2} />
        </div>

        <div className="px-8 pb-8">
          <button
            onClick={saveProfile}
            className="w-full md:w-auto px-8 py-4 rounded-2xl bg-slate-900 text-white font-black uppercase tracking-[0.2em] flex items-center justify-center gap-3 shadow-xl"
          >
            <Save size={18} />
            {isIt ? 'Salva dati profilo' : 'Save profile data'}
          </button>
        </div>
      </div>
    </div>
  );
};

const InfoRow: React.FC<{ icon: React.ReactNode; label: string; value: string }> = ({ icon, label, value }) => (
  <div className="flex items-start gap-4">
    <div className="w-12 h-12 rounded-2xl bg-slate-50 flex items-center justify-center text-slate-500">
      {icon}
    </div>
    <div>
      <p className="text-[10px] font-black uppercase tracking-widest text-slate-400">{label}</p>
      <p className="text-lg font-black text-slate-900 break-all">{value}</p>
    </div>
  </div>
);

const Field: React.FC<{ label: string; value: string; onChange: (value: string) => void; placeholder?: string; maxLength?: number; icon?: React.ReactNode }> = ({ label, value, onChange, placeholder, maxLength, icon }) => (
  <div className="space-y-2">
    <label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">{label}</label>
    <div className="relative">
      {icon && <div className="absolute left-4 top-1/2 -translate-y-1/2 text-slate-400">{icon}</div>}
      <input
        value={value}
        onChange={e => onChange(e.target.value)}
        placeholder={placeholder}
        maxLength={maxLength}
        className={`w-full px-5 py-4 rounded-2xl bg-slate-50 border border-slate-100 outline-none font-black text-sm focus:ring-4 focus:ring-blue-500/10 focus:border-blue-200 ${icon ? 'pl-11' : ''}`}
      />
    </div>
  </div>
);

export default UserProfile;

Youez - 2016 - github.com/yon3zu
LinuXploit