-
Notifications
You must be signed in to change notification settings - Fork 202
Expand file tree
/
Copy pathActivityTimeline.tsx
More file actions
88 lines (80 loc) · 2.5 KB
/
Copy pathActivityTimeline.tsx
File metadata and controls
88 lines (80 loc) · 2.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import React, { useEffect, useState } from 'react';
import './ActivityTimeline.css';
/**
* Types for activity entries. Adjust according to your backend schema.
*/
interface ActivityEntry {
id: string;
type: string; // e.g., 'borrow', 'repay', 'payment'
timestamp: string; // ISO date string
description: string;
}
/**
* ActivityTimeline component displays a list of user activities.
* Currently uses a mock fetch; replace with real API call as needed.
*/
const ActivityTimeline: React.FC = () => {
const [activities, setActivities] = useState<ActivityEntry[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
// TODO: replace mock data with real API call (e.g., fetch('/api/user/activity'))
const fetchActivities = async () => {
try {
// Simulate network delay
await new Promise(res => setTimeout(res, 500));
const mockData: ActivityEntry[] = [
{
id: '1',
type: 'borrow',
timestamp: new Date().toISOString(),
description: 'Borrowed $5,000 for home improvement',
},
{
id: '2',
type: 'repay',
timestamp: new Date(Date.now() - 86400000).toISOString(),
description: 'Repayed $500 installment',
},
];
setActivities(mockData);
setIsLoading(false);
} catch (e) {
setError('Failed to load activity');
setIsLoading(false);
}
};
fetchActivities();
}, []);
if (isLoading) {
return <div className="activity-loading" aria-live="polite">Loading activity...</div>;
}
if (error) {
return (
<div className="activity-error" role="alert">
{error}
</div>
);
}
if (activities.length === 0) {
return (
<div className="activity-empty" aria-live="polite">
No recent activity.
</div>
);
}
return (
<ul className="activity-timeline" role="list" aria-label="User activity timeline">
{activities.map(activity => (
<li key={activity.id} className="activity-item" role="listitem">
<div className="activity-type">{activity.type}</div>
<div className="activity-description">{activity.description}</div>
<time className="activity-time" dateTime={activity.timestamp}>
{new Date(activity.timestamp).toLocaleString()}
</time>
</li>
))}
</ul>
);
};
export default ActivityTimeline;