feat: integration notification functionality and user history fetching

This commit is contained in:
2025-12-23 22:10:11 +07:00
parent 797f6c2383
commit beb8ccbaee
3 changed files with 199 additions and 93 deletions

View File

@@ -46,10 +46,20 @@ const getNotificationLogByNotificationId = async (notificationId) => {
return response.data; 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 { export {
getAllNotification, getAllNotification,
getNotificationById, getNotificationById,
getNotificationDetail, getNotificationDetail,
createNotificationLog, createNotificationLog,
getNotificationLogByNotificationId getNotificationLogByNotificationId,
resendNotificationToUser,
}; };

View File

@@ -38,7 +38,11 @@ import {
SearchOutlined, SearchOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { useNavigate, Link as RouterLink } from 'react-router-dom'; 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; 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 ListNotification = memo(function ListNotification(props) {
const [notifications, setNotifications] = useState([]); const [notifications, setNotifications] = useState([]);
const [activeTab, setActiveTab] = useState('all'); const [activeTab, setActiveTab] = useState('all');
@@ -113,6 +92,8 @@ const ListNotification = memo(function ListNotification(props) {
const [selectedNotification, setSelectedNotification] = useState(null); const [selectedNotification, setSelectedNotification] = useState(null);
const [logHistoryData, setLogHistoryData] = useState([]); const [logHistoryData, setLogHistoryData] = useState([]);
const [logLoading, setLogLoading] = useState(false); const [logLoading, setLogLoading] = useState(false);
const [userHistoryData, setUserHistoryData] = useState([]);
const [userLoading, setUserLoading] = useState(false);
const [pagination, setPagination] = useState({ const [pagination, setPagination] = useState({
current_page: 1, current_page: 1,
current_limit: 10, 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) => ({ const tabButtonStyle = (isActive) => ({
padding: '12px 16px', padding: '12px 16px',
border: 'none', border: 'none',
@@ -467,8 +484,18 @@ const ListNotification = memo(function ListNotification(props) {
border: '1px solid #1890ff', border: '1px solid #1890ff',
borderRadius: '4px', borderRadius: '4px',
}} }}
onClick={(e) => { onClick={async (e) => {
e.stopPropagation(); 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'); setModalContent('user');
}} }}
/> />
@@ -535,37 +562,69 @@ const ListNotification = memo(function ListNotification(props) {
const renderUserHistory = () => ( const renderUserHistory = () => (
<> <>
<Space direction="vertical" size="middle" style={{ display: 'flex' }}> {userLoading ? (
{userHistoryData.map((user) => ( <div style={{ textAlign: 'center', padding: '24px' }}>
<Card key={user.id} style={{ borderColor: '#91d5ff' }}> <Spin size="large" />
<Row align="middle" justify="space-between"> </div>
<Col> ) : (
<Space align="center"> <Space direction="vertical" size="middle" style={{ display: 'flex' }}>
<Text strong>{user.name}</Text> {userHistoryData.map((user) => (
<Text>|</Text> <Card key={user.id} style={{ borderColor: '#91d5ff' }}>
<Text> <Row align="middle" justify="space-between">
<MobileOutlined /> {user.phone} <Col>
</Text> <Space align="center">
<Text>|</Text> <Text strong>{user.name}</Text>
<Badge status="success" text={user.status} /> <Text>|</Text>
</Space> <Text>
<Divider style={{ margin: '8px 0' }} /> <MobileOutlined /> {user.phone}
<Space align="center"> </Text>
<CheckCircleFilled style={{ color: '#52c41a' }} /> <Text>|</Text>
<Text type="secondary"> <Badge
Success Delivered at {user.timestamp} status={
</Text> user.status === 'Delivered' ? 'success' : 'default'
</Space> }
</Col> text={user.status}
<Col> />
<Button type="primary" ghost icon={<SendOutlined />}> </Space>
Resend <Divider style={{ margin: '8px 0' }} />
</Button> <Space align="center">
</Col> {user.status === 'Delivered' ? (
</Row> <CheckCircleFilled style={{ color: '#52c41a' }} />
</Card> ) : (
))} <ClockCircleOutlined style={{ color: '#faad14' }} />
</Space> )}
<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>
)}
</> </>
); );

View File

@@ -38,6 +38,7 @@ import {
getNotificationDetail, getNotificationDetail,
createNotificationLog, createNotificationLog,
getNotificationLogByNotificationId, getNotificationLogByNotificationId,
resendNotificationToUser,
} from '../../api/notification'; } from '../../api/notification';
const { Content } = Layout; const { Content } = Layout;
@@ -94,38 +95,21 @@ const transformNotificationData = (apiData) => {
device_location: apiData.device_location, device_location: apiData.device_location,
brand_name: apiData.brand_name, brand_name: apiData.brand_name,
}, },
users: apiData.users || [],
}; };
}; };
// Dummy data baru untuk user history // Function to get actual users from notification data
const getDummyUsers = (notification) => { const getUsersFromNotification = (notification) => {
if (!notification) return []; if (!notification || !notification.users) return [];
return [
{ return notification.users.map((user) => ({
id: '1', id: user.notification_error_user_id.toString(),
name: 'John Doe', name: user.contact_name,
phone: '081234567890', phone: user.contact_phone,
status: 'delivered', status: user.is_send ? 'sent' : 'pending',
}, loading: user.loading || false,
{ }));
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',
},
];
}; };
const getStatusTag = (status) => { const getStatusTag = (status) => {
@@ -469,7 +453,7 @@ const NotificationDetailTab = (props) => {
size={2} size={2}
style={{ width: '100%' }} style={{ width: '100%' }}
> >
{getDummyUsers(notification).map((user) => ( {getUsersFromNotification(notification).map((user) => (
<Card <Card
key={user.id} key={user.id}
size="small" size="small"
@@ -510,11 +494,64 @@ const NotificationDetailTab = (props) => {
type="primary" type="primary"
icon={<SendOutlined />} icon={<SendOutlined />}
size="small" size="small"
onClick={(e) => { loading={user.loading}
onClick={async (e) => {
e.stopPropagation(); e.stopPropagation();
console.log( const userId = parseInt(user.id);
`Resend to ${user.name}` 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 Resend