Files
schedtxt/src/components/ViewSentMessages.jsx
T
2026-07-04 19:39:12 -04:00

305 lines
10 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState, useEffect, useCallback } from 'react';
import { tokenService } from '../services/TokenService';
import { messageEventResponseApi } from '../api/messageEventResponseApi';
import { scheduleApi } from '../api/scheduleApi';
import './ViewSentMessages.css';
const ViewSentMessages = ({
isOpen,
onClose,
title = 'View Sent Messages',
}) => {
const [sentMessages, setSentMessages] = useState([]);
const [scheduledMessages, setScheduledMessages] = useState([]);
const [lastUpdated, setLastUpdated] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [searchTerm, setSearchTerm] = useState('');
const [activeTab, setActiveTab] = useState('sent');
// Fetch the sent messages or Message Event Responses
const fetchSentMessages = useCallback(async () => {
try {
setLoading(true);
setError(null);
const userId = tokenService.getUserId();
const response =
await messageEventResponseApi.getMessageEventResponsesByUserId(
userId,
tokenService.bearerToken()
);
if (response) {
setLastUpdated(new Date());
setSentMessages(response.data);
} else {
throw new Error(response.message || 'Failed to load sent messages');
}
} catch (err) {
setError(err.message || 'Failed to load sent messages.');
setSentMessages([]);
} finally {
setLoading(false);
}
}, []);
const fetchScheduledMessages = useCallback(async () => {
try {
const userId = tokenService.getUserId();
const response = await scheduleApi.getScheduledMessage(
userId,
tokenService.bearerToken()
);
if (response) {
const scheduledMessages = response.data;
setScheduledMessages(scheduledMessages);
} else {
throw new Error(response.message || 'Failed to get scheduled messages');
}
} catch (err) {
console.error('Failed to load scheduled messages:', err);
setScheduledMessages([]);
}
}, []);
const handleRefresh = () => {
if (activeTab === 'sent') {
fetchSentMessages();
} else {
fetchScheduledMessages();
}
};
useEffect(() => {
if (isOpen) {
console.log('Fetching sent messages');
fetchSentMessages();
}
}, [isOpen, fetchSentMessages]);
// Fetch scheduled messages when tab is switched
useEffect(() => {
if (activeTab === 'scheduled' && isOpen) {
fetchScheduledMessages();
}
}, [activeTab, isOpen, fetchScheduledMessages]);
const filteredSentMessages = sentMessages.filter((sentMessage) => {
const searchLower = searchTerm.toLowerCase();
return (
(sentMessage.status &&
sentMessage.status.toLowerCase().includes(searchLower)) ||
(sentMessage.sent &&
sentMessage.sent.toLowerCase().includes(searchLower)) ||
(sentMessage.id && sentMessage.id.toString().includes(searchTerm))
);
});
// Filter scheduled messages
const filteredScheduledMessages = scheduledMessages.filter((message) => {
const searchLower = searchTerm.toLowerCase();
return (
(message.status && message.status.toLowerCase().includes(searchLower)) ||
(message.id && message.id.toString().includes(searchTerm))
);
});
const formatLastUpdated = () => {
if (!lastUpdated) return 'Never';
return lastUpdated.toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
});
};
// Format date for scheduled messages
const formatScheduledDate = (dateString) => {
return new Date(dateString).toLocaleString();
};
// Get status badge styling
const getStatusBadgeClass = (status) => {
switch (status) {
case 'PROCESSING':
return 'status-processing';
case 'SENT':
return 'status-sent';
case 'FAILED':
return 'status-failed';
default:
return 'status-default';
}
};
if (!isOpen) return null;
return (
<div className="view-sent-message-modal-overlay" onClick={onClose}>
<div
className="view-sent-message-modal"
onClick={(e) => e.stopPropagation()}
>
<div className="view-sent-message-card">
<div className="view-sent-message-header">
<h2 className="view-sent-message-title">{title}</h2>
<button className="close-btn" onClick={onClose} aria-label="Close">
×
</button>
</div>
{/* Add tabs for navigation */}
<div className="view-sent-message-tabs">
<button
className={`tab-button ${activeTab === 'sent' ? 'active' : ''}`}
onClick={() => setActiveTab('sent')}
>
Sent Messages
</button>
<button
className={`tab-button ${activeTab === 'scheduled' ? 'active' : ''}`}
onClick={() => setActiveTab('scheduled')}
>
Scheduled Messages
</button>
</div>
{/* Search input */}
<div className="search-container">
<input
type="text"
placeholder="Search messages..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="search-input"
/>
</div>
<div className="view-sent-message-form">
{error && (
<div className="submit-error">
<div style={{ marginBottom: '8px' }}>{error}</div>
<button
onClick={handleRefresh}
style={{
background: '#ef4444',
color: 'white',
border: 'none',
borderRadius: '4px',
padding: '6px 12px',
cursor: 'pointer',
fontSize: '12px',
}}
>
Retry Now
</button>
</div>
)}
{loading ? (
<div style={{ textAlign: 'center', padding: '40px' }}>
<div className="loading-spinner" />
<p>Loading messages...</p>
</div>
) : (
<>
{/* Sent Messages Tab Content */}
{activeTab === 'sent' && (
<div className="messages-section">
<div className="section-header">
<h3>Sent Messages</h3>
<span className="last-updated">
Last updated: {formatLastUpdated()}
</span>
</div>
{filteredSentMessages.length > 0 ? (
<div className="view-sent-message-list-container">
<table className="view-sent-message-table">
<thead>
<tr>
<th>ID</th>
<th>Status</th>
<th>Sent Time</th>
</tr>
</thead>
<tbody>
{filteredSentMessages.map((message) => (
<tr key={message.id}>
<td>{message.id.substring(0, 8)}...</td>
<td>
<span
className={`status-badge ${getStatusBadgeClass(message.status)}`}
>
{message.status}
</span>
</td>
<td>{message.sent || 'N/A'}</td>
</tr>
))}
</tbody>
</table>
</div>
) : (
<div className="no-messages">No sent messages found.</div>
)}
</div>
)}
{/* Scheduled Messages Tab Content */}
{activeTab === 'scheduled' && (
<div className="messages-section">
<div className="section-header">
<h3>Scheduled Messages</h3>
</div>
{filteredScheduledMessages.length > 0 ? (
<div className="view-sent-message-list-container">
<table className="view-sent-message-table">
<thead>
<tr>
<th>ID</th>
<th>Scheduled Time</th>
<th>Created Time</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{filteredScheduledMessages.map((message) => (
<tr key={message.id}>
<td>{message.id.substring(0, 8)}...</td>
<td>
{formatScheduledDate(message.scheduled)}
</td>
<td>{formatScheduledDate(message.created)}</td>
<td>
<span
className={`status-badge ${getStatusBadgeClass(message.status)}`}
>
{message.status}
</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
) : (
<div className="no-messages">
No scheduled messages found.
</div>
)}
</div>
)}
</>
)}
</div>
</div>
</div>
</div>
);
};
export default ViewSentMessages;