FEAT: Adição de horas as mensgens
This commit is contained in:
parent
217d566057
commit
2e97ac6e5a
@ -23,13 +23,8 @@ function ChannelBadge({ channel }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function PresenceDot({ status }) {
|
function ActivityDot({ status }) {
|
||||||
const color =
|
const color = status === 'away' ? '#e5a22a' : '#dc2626';
|
||||||
status === 'online'
|
|
||||||
? '#16a34a'
|
|
||||||
: status === 'away'
|
|
||||||
? '#e5a22a'
|
|
||||||
: '#dc2626';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
@ -134,7 +129,7 @@ export function ChatConversationList({
|
|||||||
>
|
>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem' }}>
|
||||||
<span style={{ display: 'inline-flex', alignItems: 'center', gap: '0.5rem', minWidth: 0 }}>
|
<span style={{ display: 'inline-flex', alignItems: 'center', gap: '0.5rem', minWidth: 0 }}>
|
||||||
<PresenceDot status={contact.status} />
|
<ActivityDot status={contact.status} />
|
||||||
<strong style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
<strong style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
||||||
{contact.name}
|
{contact.name}
|
||||||
</strong>
|
</strong>
|
||||||
|
|||||||
@ -22,6 +22,13 @@ function parseMessageText(text) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatMessageTime(timestamp) {
|
||||||
|
if (!timestamp) return '';
|
||||||
|
const numericTimestamp = Number(timestamp);
|
||||||
|
const date = new Date(numericTimestamp > 1000000000000 ? numericTimestamp : numericTimestamp * 1000);
|
||||||
|
return date.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' });
|
||||||
|
}
|
||||||
|
|
||||||
function MediaRenderer({ message, contactId, onLoadMedia, isAgent }) {
|
function MediaRenderer({ message, contactId, onLoadMedia, isAgent }) {
|
||||||
const mediaUrl = useMemo(() => getMediaUrl(message.media), [message.media]);
|
const mediaUrl = useMemo(() => getMediaUrl(message.media), [message.media]);
|
||||||
const mimetype = message.media?.mimetype || '';
|
const mimetype = message.media?.mimetype || '';
|
||||||
@ -196,19 +203,14 @@ function AttachmentPreview({ file, onRemove }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ContactPresence({ contact }) {
|
function ContactActivity({ contact }) {
|
||||||
if (!contact) {
|
if (!contact) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const status = contact.status || 'offline';
|
const status = contact.status || 'offline';
|
||||||
const color =
|
const color = status === 'away' ? '#e5a22a' : '#dc2626';
|
||||||
status === 'online'
|
const label = contact.lastSeen || 'Sem atividade recente';
|
||||||
? '#16a34a'
|
|
||||||
: status === 'away'
|
|
||||||
? '#e5a22a'
|
|
||||||
: '#dc2626';
|
|
||||||
const label = status === 'online' ? 'Online agora' : contact.lastSeen || 'Offline';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
@ -301,7 +303,7 @@ export function ChatWindow({
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<strong style={{ display: 'block', fontSize: '1.15rem' }}>{safeContact.name}</strong>
|
<strong style={{ display: 'block', fontSize: '1.15rem' }}>{safeContact.name}</strong>
|
||||||
<ContactPresence contact={safeContact} />
|
<ContactActivity contact={safeContact} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@ -397,6 +399,7 @@ export function ChatWindow({
|
|||||||
const isAgent = message.sender === 'agent';
|
const isAgent = message.sender === 'agent';
|
||||||
const isSystem = message.sender === 'system';
|
const isSystem = message.sender === 'system';
|
||||||
const parsedText = parseMessageText(message.text);
|
const parsedText = parseMessageText(message.text);
|
||||||
|
const messageTime = formatMessageTime(message.timestamp);
|
||||||
|
|
||||||
if (isSystem) {
|
if (isSystem) {
|
||||||
return (
|
return (
|
||||||
@ -464,6 +467,18 @@ export function ChatWindow({
|
|||||||
{parsedText.body}
|
{parsedText.body}
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
|
{messageTime ? (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
justifySelf: 'end',
|
||||||
|
fontSize: '0.72rem',
|
||||||
|
lineHeight: 1,
|
||||||
|
color: isAgent ? 'rgba(255,255,255,0.7)' : 'var(--color-text-soft)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{messageTime}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@ -38,22 +38,17 @@ function getPreviewFromMessage(message) {
|
|||||||
|
|
||||||
function normalizeChat(chat) {
|
function normalizeChat(chat) {
|
||||||
const id = getSerializedId(chat.id);
|
const id = getSerializedId(chat.id);
|
||||||
const lastActivitySeconds = chat.timestamp ? Math.floor(Date.now() / 1000) - chat.timestamp : null;
|
|
||||||
const isRecentlyActive = lastActivitySeconds !== null && lastActivitySeconds < 300;
|
|
||||||
const assignment = chat.assignment || null;
|
const assignment = chat.assignment || null;
|
||||||
|
const lastSeenTimestamp = chat.timestamp || null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
name: getContactName(chat),
|
name: getContactName(chat),
|
||||||
channel: 'WhatsApp',
|
channel: 'WhatsApp',
|
||||||
status: isRecentlyActive ? 'online' : 'away',
|
status: lastSeenTimestamp ? 'away' : 'offline',
|
||||||
area: assignment?.area_nome || (assignment?.area_id ? String(assignment.area_id) : 'Sem fila'),
|
area: assignment?.area_nome || (assignment?.area_id ? String(assignment.area_id) : 'Sem fila'),
|
||||||
areaId: assignment?.area_id || null,
|
areaId: assignment?.area_id || null,
|
||||||
lastSeen: isRecentlyActive
|
lastSeen: lastSeenTimestamp ? `Ultima atividade as ${formatTime(lastSeenTimestamp)}` : 'Sem atividade recente',
|
||||||
? 'Online agora'
|
|
||||||
: chat.timestamp
|
|
||||||
? `Visto as ${formatTime(chat.timestamp)}`
|
|
||||||
: 'Sem atividade recente',
|
|
||||||
preview: chat.preview || chat.lastMessage?.body || '',
|
preview: chat.preview || chat.lastMessage?.body || '',
|
||||||
time: formatTime(chat.timestamp) || 'Agora',
|
time: formatTime(chat.timestamp) || 'Agora',
|
||||||
unread: chat.unreadCount || 0,
|
unread: chat.unreadCount || 0,
|
||||||
@ -77,6 +72,11 @@ function normalizeMessage(message) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDisplayableMessage(message) {
|
||||||
|
const text = String(message?.text ?? message?.body ?? '').trim();
|
||||||
|
return Boolean(text || message?.hasMedia || message?.media);
|
||||||
|
}
|
||||||
|
|
||||||
function getComparableMessageTime(message) {
|
function getComparableMessageTime(message) {
|
||||||
if (message.timestamp) return Number(message.timestamp);
|
if (message.timestamp) return Number(message.timestamp);
|
||||||
if (typeof message.id === 'string' && message.id.startsWith('temp-')) {
|
if (typeof message.id === 'string' && message.id.startsWith('temp-')) {
|
||||||
@ -316,10 +316,12 @@ export function useChat() {
|
|||||||
setMessagesByContact((current) => ({
|
setMessagesByContact((current) => ({
|
||||||
...current,
|
...current,
|
||||||
[activeContactId]: dedupeMessages(
|
[activeContactId]: dedupeMessages(
|
||||||
data.map((message) => ({
|
data
|
||||||
|
.map((message) => ({
|
||||||
...normalizeMessage(message),
|
...normalizeMessage(message),
|
||||||
chatId: activeContactId,
|
chatId: activeContactId,
|
||||||
})),
|
}))
|
||||||
|
.filter(isDisplayableMessage),
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
setApiError(null);
|
setApiError(null);
|
||||||
@ -345,6 +347,10 @@ export function useChat() {
|
|||||||
...normalizeMessage(incomingMessage),
|
...normalizeMessage(incomingMessage),
|
||||||
chatId: contactId,
|
chatId: contactId,
|
||||||
};
|
};
|
||||||
|
if (!isDisplayableMessage(message)) {
|
||||||
|
clearIncomingMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const preview = getPreviewFromMessage(message);
|
const preview = getPreviewFromMessage(message);
|
||||||
|
|
||||||
setMessagesByContact((current) => {
|
setMessagesByContact((current) => {
|
||||||
@ -367,14 +373,16 @@ export function useChat() {
|
|||||||
id: contactId,
|
id: contactId,
|
||||||
name: incomingMessage.notifyName || contactId.split('@')[0],
|
name: incomingMessage.notifyName || contactId.split('@')[0],
|
||||||
channel: 'WhatsApp',
|
channel: 'WhatsApp',
|
||||||
status: 'online',
|
status: 'away',
|
||||||
area: 'Sem fila',
|
area: 'Sem fila',
|
||||||
lastSeen: 'Online agora',
|
lastSeen: 'Visto agora',
|
||||||
unread: 0,
|
unread: 0,
|
||||||
assignment: null,
|
assignment: null,
|
||||||
}),
|
}),
|
||||||
preview,
|
preview,
|
||||||
time: 'Agora',
|
time: 'Agora',
|
||||||
|
status: 'away',
|
||||||
|
lastSeen: 'Ultima atividade agora',
|
||||||
unread:
|
unread:
|
||||||
incomingMessage.fromMe || contactId === activeContactRef.current
|
incomingMessage.fromMe || contactId === activeContactRef.current
|
||||||
? 0
|
? 0
|
||||||
|
|||||||
@ -3,9 +3,9 @@ export const chatContacts = [
|
|||||||
id: 'maria-souza',
|
id: 'maria-souza',
|
||||||
name: 'Maria Souza',
|
name: 'Maria Souza',
|
||||||
channel: 'WhatsApp',
|
channel: 'WhatsApp',
|
||||||
status: 'online',
|
status: 'away',
|
||||||
area: 'Suporte',
|
area: 'Suporte',
|
||||||
lastSeen: 'Online agora',
|
lastSeen: 'Ultima atividade as 09:42',
|
||||||
preview: 'Preciso atualizar o cadastro do meu pedido.',
|
preview: 'Preciso atualizar o cadastro do meu pedido.',
|
||||||
time: '09:42',
|
time: '09:42',
|
||||||
unread: 2,
|
unread: 2,
|
||||||
@ -22,7 +22,7 @@ export const chatContacts = [
|
|||||||
channel: 'SMS',
|
channel: 'SMS',
|
||||||
status: 'offline',
|
status: 'offline',
|
||||||
area: 'Financeiro',
|
area: 'Financeiro',
|
||||||
lastSeen: 'Visto ha 12 min',
|
lastSeen: 'Ultima atividade as 08:15',
|
||||||
preview: 'Pode me ligar em 10 minutos?',
|
preview: 'Pode me ligar em 10 minutos?',
|
||||||
time: '08:15',
|
time: '08:15',
|
||||||
unread: 1,
|
unread: 1,
|
||||||
|
|||||||
@ -301,7 +301,7 @@ export function MessagesWorkspace({
|
|||||||
{safeActiveConversation.name}
|
{safeActiveConversation.name}
|
||||||
</strong>
|
</strong>
|
||||||
<span style={{ color: 'var(--color-text-soft)' }}>
|
<span style={{ color: 'var(--color-text-soft)' }}>
|
||||||
{safeActiveConversation.status === 'online' ? 'Online agora' : 'Offline'}
|
{safeActiveConversation.lastSeen || 'Sem atividade recente'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', gap: '0.6rem', flexWrap: 'wrap' }}>
|
<div style={{ display: 'flex', gap: '0.6rem', flexWrap: 'wrap' }}>
|
||||||
|
|||||||
@ -7,7 +7,6 @@ export function useWhatsappSocket() {
|
|||||||
const [qrCode, setQrCode] = useState(null);
|
const [qrCode, setQrCode] = useState(null);
|
||||||
const [status, setStatus] = useState('DISCONNECTED');
|
const [status, setStatus] = useState('DISCONNECTED');
|
||||||
const [incomingMessage, setIncomingMessage] = useState(null);
|
const [incomingMessage, setIncomingMessage] = useState(null);
|
||||||
const [presenceUpdate, setPresenceUpdate] = useState(null);
|
|
||||||
const socketRef = useRef(null);
|
const socketRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -44,11 +43,6 @@ export function useWhatsappSocket() {
|
|||||||
setIncomingMessage(message);
|
setIncomingMessage(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
newSocket.on('presence', (presence) => {
|
|
||||||
console.log('Atualização de presença:', presence);
|
|
||||||
setPresenceUpdate(presence);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
newSocket.disconnect();
|
newSocket.disconnect();
|
||||||
socketRef.current = null;
|
socketRef.current = null;
|
||||||
@ -60,8 +54,6 @@ export function useWhatsappSocket() {
|
|||||||
qrCode,
|
qrCode,
|
||||||
status,
|
status,
|
||||||
incomingMessage,
|
incomingMessage,
|
||||||
presenceUpdate,
|
|
||||||
clearIncomingMessage: () => setIncomingMessage(null),
|
clearIncomingMessage: () => setIncomingMessage(null),
|
||||||
clearPresenceUpdate: () => setPresenceUpdate(null)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user