feat: integration notification functionality and user history fetching
This commit is contained in:
@@ -46,10 +46,20 @@ const getNotificationLogByNotificationId = async (notificationId) => {
|
||||
return response.data;
|
||||
};
|
||||
|
||||
// Resend notification to specific user
|
||||
const resendNotificationToUser = async (notificationId, userId) => {
|
||||
const response = await SendRequest({
|
||||
method: 'post',
|
||||
prefix: `notification/${notificationId}/resend/${userId}`,
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export {
|
||||
getAllNotification,
|
||||
getNotificationById,
|
||||
getNotificationDetail,
|
||||
createNotificationLog,
|
||||
getNotificationLogByNotificationId
|
||||
getNotificationLogByNotificationId,
|
||||
resendNotificationToUser,
|
||||
};
|
||||
|
||||
@@ -38,7 +38,11 @@ import {
|
||||
SearchOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useNavigate, Link as RouterLink } from 'react-router-dom';
|
||||
import { getAllNotification, getNotificationLogByNotificationId } from '../../../api/notification';
|
||||
import {
|
||||
getAllNotification,
|
||||
getNotificationLogByNotificationId,
|
||||
getNotificationDetail,
|
||||
} from '../../../api/notification';
|
||||
|
||||
const { Text, Paragraph, Link: AntdLink } = Typography;
|
||||
|
||||
@@ -77,31 +81,6 @@ const transformNotificationData = (apiData) => {
|
||||
}));
|
||||
};
|
||||
|
||||
// Dummy data untuk user history
|
||||
const userHistoryData = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'John Doe',
|
||||
phone: '081234567890',
|
||||
status: 'Delivered',
|
||||
timestamp: '04-11-2025 11:40 WIB',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Jane Smith',
|
||||
phone: '087654321098',
|
||||
status: 'Delivered',
|
||||
timestamp: '04-11-2025 11:41 WIB',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Peter Jones',
|
||||
phone: '082345678901',
|
||||
status: 'Delivered',
|
||||
timestamp: '04-11-2025 11:42 WIB',
|
||||
},
|
||||
];
|
||||
|
||||
const ListNotification = memo(function ListNotification(props) {
|
||||
const [notifications, setNotifications] = useState([]);
|
||||
const [activeTab, setActiveTab] = useState('all');
|
||||
@@ -113,6 +92,8 @@ const ListNotification = memo(function ListNotification(props) {
|
||||
const [selectedNotification, setSelectedNotification] = useState(null);
|
||||
const [logHistoryData, setLogHistoryData] = useState([]);
|
||||
const [logLoading, setLogLoading] = useState(false);
|
||||
const [userHistoryData, setUserHistoryData] = useState([]);
|
||||
const [userLoading, setUserLoading] = useState(false);
|
||||
const [pagination, setPagination] = useState({
|
||||
current_page: 1,
|
||||
current_limit: 10,
|
||||
@@ -290,6 +271,42 @@ const ListNotification = memo(function ListNotification(props) {
|
||||
}
|
||||
};
|
||||
|
||||
// Fetch user history from API
|
||||
const fetchUserHistory = async (notificationId) => {
|
||||
try {
|
||||
setUserLoading(true);
|
||||
|
||||
const response = await getNotificationDetail(notificationId);
|
||||
|
||||
if (response && response.data && response.data.users) {
|
||||
// Transform API data to component format
|
||||
const transformedUsers = response.data.users.map((user) => ({
|
||||
id: user.notification_error_user_id.toString(),
|
||||
name: user.contact_name,
|
||||
phone: user.contact_phone,
|
||||
status: user.is_send ? 'Delivered' : 'Pending',
|
||||
timestamp: user.created_at
|
||||
? new Date(user.created_at).toLocaleString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
}) + ' WIB'
|
||||
: 'N/A',
|
||||
}));
|
||||
setUserHistoryData(transformedUsers);
|
||||
} else {
|
||||
setUserHistoryData([]);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error fetching user history:', err);
|
||||
setUserHistoryData([]); // Set empty array on error
|
||||
} finally {
|
||||
setUserLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const tabButtonStyle = (isActive) => ({
|
||||
padding: '12px 16px',
|
||||
border: 'none',
|
||||
@@ -467,8 +484,18 @@ const ListNotification = memo(function ListNotification(props) {
|
||||
border: '1px solid #1890ff',
|
||||
borderRadius: '4px',
|
||||
}}
|
||||
onClick={(e) => {
|
||||
onClick={async (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
setSelectedNotification(notification);
|
||||
|
||||
// Extract notification ID from the notification object
|
||||
const notificationId =
|
||||
notification.id.split('-')[1];
|
||||
|
||||
// Fetch user history for the selected notification
|
||||
await fetchUserHistory(notificationId);
|
||||
|
||||
setModalContent('user');
|
||||
}}
|
||||
/>
|
||||
@@ -535,37 +562,69 @@ const ListNotification = memo(function ListNotification(props) {
|
||||
|
||||
const renderUserHistory = () => (
|
||||
<>
|
||||
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
||||
{userHistoryData.map((user) => (
|
||||
<Card key={user.id} style={{ borderColor: '#91d5ff' }}>
|
||||
<Row align="middle" justify="space-between">
|
||||
<Col>
|
||||
<Space align="center">
|
||||
<Text strong>{user.name}</Text>
|
||||
<Text>|</Text>
|
||||
<Text>
|
||||
<MobileOutlined /> {user.phone}
|
||||
</Text>
|
||||
<Text>|</Text>
|
||||
<Badge status="success" text={user.status} />
|
||||
</Space>
|
||||
<Divider style={{ margin: '8px 0' }} />
|
||||
<Space align="center">
|
||||
<CheckCircleFilled style={{ color: '#52c41a' }} />
|
||||
<Text type="secondary">
|
||||
Success Delivered at {user.timestamp}
|
||||
</Text>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col>
|
||||
<Button type="primary" ghost icon={<SendOutlined />}>
|
||||
Resend
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
))}
|
||||
</Space>
|
||||
{userLoading ? (
|
||||
<div style={{ textAlign: 'center', padding: '24px' }}>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
) : (
|
||||
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
||||
{userHistoryData.map((user) => (
|
||||
<Card key={user.id} style={{ borderColor: '#91d5ff' }}>
|
||||
<Row align="middle" justify="space-between">
|
||||
<Col>
|
||||
<Space align="center">
|
||||
<Text strong>{user.name}</Text>
|
||||
<Text>|</Text>
|
||||
<Text>
|
||||
<MobileOutlined /> {user.phone}
|
||||
</Text>
|
||||
<Text>|</Text>
|
||||
<Badge
|
||||
status={
|
||||
user.status === 'Delivered' ? 'success' : 'default'
|
||||
}
|
||||
text={user.status}
|
||||
/>
|
||||
</Space>
|
||||
<Divider style={{ margin: '8px 0' }} />
|
||||
<Space align="center">
|
||||
{user.status === 'Delivered' ? (
|
||||
<CheckCircleFilled style={{ color: '#52c41a' }} />
|
||||
) : (
|
||||
<ClockCircleOutlined style={{ color: '#faad14' }} />
|
||||
)}
|
||||
<Text type="secondary">
|
||||
{user.status === 'Delivered'
|
||||
? 'Success Delivered at'
|
||||
: 'Status '}{' '}
|
||||
{user.timestamp}
|
||||
</Text>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col>
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
icon={<SendOutlined />}
|
||||
onClick={() => {
|
||||
message.info(
|
||||
'Resend feature is not available yet. This feature is still under development.'
|
||||
);
|
||||
}}
|
||||
>
|
||||
Resend
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
))}
|
||||
{userHistoryData.length === 0 && (
|
||||
<div style={{ textAlign: 'center', padding: '24px', color: '#8c8c8c' }}>
|
||||
No user history available
|
||||
</div>
|
||||
)}
|
||||
</Space>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
getNotificationDetail,
|
||||
createNotificationLog,
|
||||
getNotificationLogByNotificationId,
|
||||
resendNotificationToUser,
|
||||
} from '../../api/notification';
|
||||
|
||||
const { Content } = Layout;
|
||||
@@ -94,38 +95,21 @@ const transformNotificationData = (apiData) => {
|
||||
device_location: apiData.device_location,
|
||||
brand_name: apiData.brand_name,
|
||||
},
|
||||
users: apiData.users || [],
|
||||
};
|
||||
};
|
||||
|
||||
// Dummy data baru untuk user history
|
||||
const getDummyUsers = (notification) => {
|
||||
if (!notification) return [];
|
||||
return [
|
||||
{
|
||||
id: '1',
|
||||
name: 'John Doe',
|
||||
phone: '081234567890',
|
||||
status: 'delivered',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Jane Smith',
|
||||
phone: '082345678901',
|
||||
status: 'sent',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Bob Johnson',
|
||||
phone: '083456789012',
|
||||
status: 'failed',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'Alice Brown',
|
||||
phone: '084567890123',
|
||||
status: 'delivered',
|
||||
},
|
||||
];
|
||||
// Function to get actual users from notification data
|
||||
const getUsersFromNotification = (notification) => {
|
||||
if (!notification || !notification.users) return [];
|
||||
|
||||
return notification.users.map((user) => ({
|
||||
id: user.notification_error_user_id.toString(),
|
||||
name: user.contact_name,
|
||||
phone: user.contact_phone,
|
||||
status: user.is_send ? 'sent' : 'pending',
|
||||
loading: user.loading || false,
|
||||
}));
|
||||
};
|
||||
|
||||
const getStatusTag = (status) => {
|
||||
@@ -469,7 +453,7 @@ const NotificationDetailTab = (props) => {
|
||||
size={2}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
{getDummyUsers(notification).map((user) => (
|
||||
{getUsersFromNotification(notification).map((user) => (
|
||||
<Card
|
||||
key={user.id}
|
||||
size="small"
|
||||
@@ -510,11 +494,64 @@ const NotificationDetailTab = (props) => {
|
||||
type="primary"
|
||||
icon={<SendOutlined />}
|
||||
size="small"
|
||||
onClick={(e) => {
|
||||
loading={user.loading}
|
||||
onClick={async (e) => {
|
||||
e.stopPropagation();
|
||||
console.log(
|
||||
`Resend to ${user.name}`
|
||||
);
|
||||
const userId = parseInt(user.id);
|
||||
try {
|
||||
// Update user status to show loading
|
||||
const updatedUsers = notification.users.map(u =>
|
||||
u.notification_error_user_id === userId
|
||||
? { ...u, loading: true }
|
||||
: u
|
||||
);
|
||||
setNotification({
|
||||
...notification,
|
||||
users: updatedUsers
|
||||
});
|
||||
|
||||
// Call the resend API
|
||||
const response = await resendNotificationToUser(
|
||||
notification.notification_error_id,
|
||||
userId
|
||||
);
|
||||
|
||||
if (response && response.statusCode === 200) {
|
||||
message.success(`Notification resent to ${user.name}`);
|
||||
|
||||
// Update user status
|
||||
const updatedUsersAfterSuccess = notification.users.map(u =>
|
||||
u.notification_error_user_id === userId
|
||||
? {
|
||||
...u,
|
||||
is_send: true,
|
||||
status: 'sent',
|
||||
loading: false
|
||||
}
|
||||
: { ...u, loading: false }
|
||||
);
|
||||
setNotification({
|
||||
...notification,
|
||||
users: updatedUsersAfterSuccess
|
||||
});
|
||||
} else {
|
||||
throw new Error(response?.message || 'Failed to resend notification');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error resending notification:', error);
|
||||
message.error(error.message || 'Failed to resend notification');
|
||||
|
||||
// Reset loading state
|
||||
const resetUsers = notification.users.map(u =>
|
||||
u.notification_error_user_id === userId
|
||||
? { ...u, loading: false }
|
||||
: u
|
||||
);
|
||||
setNotification({
|
||||
...notification,
|
||||
users: resetUsers
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
Resend
|
||||
|
||||
Reference in New Issue
Block a user