omnichannel-frontend/src/modules/chat/components/ContactProfilePanel.jsx
Rafael Lopes faa03f80cf
Some checks are pending
Deploy Dev / deploy (push) Waiting to run
REFACTOR: Ajustes de borda e modal de novo template
- Ajustado border Radius de todos componentes de 28 para 20px
- Criado modal para quando for criado um novo template
2026-06-24 14:46:00 -03:00

198 lines
5.6 KiB
JavaScript

import { useEffect, useState } from 'react';
import { getCurrentUser } from '../../auth/services/sessionService';
import { getContactProfile, saveContactProfile } from '../services/contactProfileService';
function getUserId(user) {
const value = user?.databaseId || user?.id;
const numeric = Number(value);
return Number.isFinite(numeric) ? numeric : null;
}
function formatPhone(phone) {
const digits = String(phone || '').replace(/\D/g, '');
if (!digits) return 'Telefone não disponível';
if (digits.startsWith('55') && digits.length === 13) {
return `+55 (${digits.slice(2, 4)}) ${digits.slice(4, 9)}-${digits.slice(9)}`;
}
if (digits.startsWith('55') && digits.length === 12) {
return `+55 (${digits.slice(2, 4)}) ${digits.slice(4, 8)}-${digits.slice(8)}`;
}
if (digits.length === 11) {
return `(${digits.slice(0, 2)}) ${digits.slice(2, 7)}-${digits.slice(7)}`;
}
if (digits.length === 10) {
return `(${digits.slice(0, 2)}) ${digits.slice(2, 6)}-${digits.slice(6)}`;
}
return phone;
}
export function ContactProfilePanel({ isOpen, contact, onClose, onSaved }) {
const [profile, setProfile] = useState(null);
const [form, setForm] = useState({ name: '', company: '', note: '' });
const [isSaving, setIsSaving] = useState(false);
const [error, setError] = useState('');
useEffect(() => {
let isMounted = true;
async function loadProfile() {
if (!isOpen || !contact?.id) return;
try {
const data = await getContactProfile(contact.id);
if (!isMounted) return;
setProfile(data);
setForm({
name: data.name || contact.name || '',
company: data.company || '',
note: data.note || '',
});
setError('');
} catch (err) {
if (isMounted) setError(err.message);
}
}
loadProfile();
return () => {
isMounted = false;
};
}, [isOpen, contact?.id]);
if (!isOpen) {
return null;
}
const fieldStyle = {
width: '100%',
border: '1px solid var(--color-border)',
borderRadius: '12px',
padding: '0.9rem 1rem',
background: '#fff',
outline: 'none',
};
async function submit() {
if (!contact?.id) return;
setIsSaving(true);
try {
const userId = getUserId(getCurrentUser());
const saved = await saveContactProfile(contact.id, {
phone: profile?.phone || contact?.contactProfile?.phone || '',
name: form.name,
company: form.company,
note: form.note,
userId,
});
setProfile(saved);
onSaved?.(contact.id, saved);
setError('');
} catch (err) {
setError(err.message);
} finally {
setIsSaving(false);
}
}
return (
<aside
style={{
background: '#fff',
border: '1px solid var(--color-border)',
borderRadius: '20px',
padding: '1.25rem',
display: 'grid',
gap: '1rem',
}}
>
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem' }}>
<div>
<strong style={{ display: 'block', fontSize: '1.06rem' }}>Contato do cliente</strong>
<span style={{ color: 'var(--color-text-soft)' }}>
Atualize os dados de agenda deste atendimento.
</span>
</div>
<button
type="button"
onClick={onClose}
style={{
border: 'none',
background: 'transparent',
color: 'var(--color-text-soft)',
fontWeight: 700,
}}
>
Fechar
</button>
</div>
<label style={{ display: 'grid', gap: '0.45rem' }}>
<span style={{ fontWeight: 600 }}>Nome</span>
<input
value={form.name}
onChange={(event) => setForm((current) => ({ ...current, name: event.target.value }))}
style={fieldStyle}
/>
</label>
<label style={{ display: 'grid', gap: '0.45rem' }}>
<span style={{ fontWeight: 600 }}>Etiqueta de identificação</span>
<input
value={form.company}
onChange={(event) => setForm((current) => ({ ...current, company: event.target.value }))}
placeholder="Ex: Departamento, vaga ou conta vinculada"
style={fieldStyle}
/>
</label>
<label style={{ display: 'grid', gap: '0.45rem' }}>
<span style={{ fontWeight: 600 }}>Telefone</span>
<input
value={formatPhone(profile?.phone || contact?.contactProfile?.phone)}
disabled
style={{
...fieldStyle,
background: 'rgba(0, 49, 80, 0.04)',
color: 'var(--color-text-soft)',
fontWeight: 700,
}}
/>
</label>
<label style={{ display: 'grid', gap: '0.45rem' }}>
<span style={{ fontWeight: 600 }}>Observação</span>
<textarea
rows={5}
value={form.note}
onChange={(event) => setForm((current) => ({ ...current, note: event.target.value }))}
placeholder="Informações relevantes do cliente."
style={{ ...fieldStyle, resize: 'vertical' }}
/>
</label>
{error ? <span style={{ color: '#b42318', fontWeight: 700 }}>{error}</span> : null}
<button
type="button"
onClick={submit}
disabled={isSaving}
style={{
border: 'none',
borderRadius: '12px',
padding: '0.95rem 1rem',
background: 'linear-gradient(135deg, var(--color-primary), #0b5a86)',
color: '#fff',
fontWeight: 700,
opacity: isSaving ? 0.65 : 1,
}}
>
{isSaving ? 'Salvando...' : 'Salvar contato'}
</button>
</aside>
);
}