Skip to content

Commit d80e9ce

Browse files
Copilot0xrinegade
andcommitted
Convert profile tabs to property-value table layouts
Co-authored-by: 0xrinegade <[email protected]>
1 parent c594fec commit d80e9ce

File tree

8 files changed

+1350
-530
lines changed

8 files changed

+1350
-530
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
/**
5+
* PropertyValueTable component displays data in a table format with property names and values
6+
*/
7+
const PropertyValueTable = ({ title, data, className = '', actions = null }) => {
8+
if (!data || data.length === 0) {
9+
return (
10+
<div className={`property-value-table card ${className}`}>
11+
{title && (
12+
<div className="card-header">
13+
<h3 className="card-title">{title}</h3>
14+
</div>
15+
)}
16+
<div className="ascii-form-message no-data">
17+
<span className="message-icon">[!]</span>
18+
<span className="message-text">NO DATA AVAILABLE</span>
19+
</div>
20+
</div>
21+
);
22+
}
23+
24+
return (
25+
<div className={`property-value-table card ${className}`}>
26+
{title && (
27+
<div className="card-header">
28+
<h3 className="card-title">{title}</h3>
29+
{actions && <div className="card-actions">{actions}</div>}
30+
</div>
31+
)}
32+
33+
<div className="ascii-table">
34+
<div className="ascii-table-header">
35+
<div className="ascii-table-col property-col">PROPERTY</div>
36+
<div className="ascii-table-col value-col">VALUE</div>
37+
</div>
38+
39+
{data.map((item, index) => (
40+
<div key={index} className={`ascii-table-row ${item.className || ''}`}>
41+
<div className="ascii-table-col property-col">
42+
<span className="property-name">{item.property}</span>
43+
{item.description && (
44+
<div className="property-description">{item.description}</div>
45+
)}
46+
</div>
47+
<div className="ascii-table-col value-col">
48+
<span className={`property-value ${item.valueClassName || ''}`}>
49+
{item.value}
50+
</span>
51+
{item.badge && (
52+
<span className={`property-badge ${item.badgeClassName || ''}`}>
53+
{item.badge}
54+
</span>
55+
)}
56+
</div>
57+
</div>
58+
))}
59+
</div>
60+
</div>
61+
);
62+
};
63+
64+
PropertyValueTable.propTypes = {
65+
title: PropTypes.string,
66+
data: PropTypes.arrayOf(
67+
PropTypes.shape({
68+
property: PropTypes.string.isRequired,
69+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.node]).isRequired,
70+
description: PropTypes.string,
71+
className: PropTypes.string,
72+
valueClassName: PropTypes.string,
73+
badge: PropTypes.string,
74+
badgeClassName: PropTypes.string,
75+
})
76+
).isRequired,
77+
className: PropTypes.string,
78+
actions: PropTypes.node,
79+
};
80+
81+
export default PropertyValueTable;

src/components/profile/ActivityFeed.js

Lines changed: 53 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
3+
import PropertyValueTable from '../common/PropertyValueTable';
34

45
/**
56
* ActivityFeed component displays the user's recent activity
@@ -12,121 +13,73 @@ const ActivityFeed = ({ activities }) => {
1213
const diffInSeconds = Math.floor((now - activityTime) / 1000);
1314

1415
if (diffInSeconds < 60) {
15-
return 'just now';
16+
return 'JUST NOW';
1617
} else if (diffInSeconds < 3600) {
1718
const minutes = Math.floor(diffInSeconds / 60);
18-
return `${minutes} minute${minutes > 1 ? 's' : ''} ago`;
19+
return `${minutes} MINUTE${minutes > 1 ? 'S' : ''} AGO`;
1920
} else if (diffInSeconds < 86400) {
2021
const hours = Math.floor(diffInSeconds / 3600);
21-
return `${hours} hour${hours > 1 ? 's' : ''} ago`;
22+
return `${hours} HOUR${hours > 1 ? 'S' : ''} AGO`;
2223
} else if (diffInSeconds < 604800) {
2324
const days = Math.floor(diffInSeconds / 86400);
24-
return `${days} day${days > 1 ? 's' : ''} ago`;
25+
return `${days} DAY${days > 1 ? 'S' : ''} AGO`;
2526
} else {
26-
return activityTime.toLocaleDateString();
27+
return activityTime.toLocaleDateString().toUpperCase();
2728
}
2829
};
2930

30-
// Get icon for activity type
31+
// Get activity type icon as text
3132
const getActivityIcon = (type) => {
3233
switch (type) {
33-
case 'trade':
34-
return (
35-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="20" height="20">
36-
<path d="M8 5v14l11-7z" />
37-
</svg>
38-
);
39-
case 'offer':
40-
return (
41-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="20" height="20">
42-
<path d="M21 18v1c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V5c0-1.1.9-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" />
43-
</svg>
44-
);
45-
case 'dispute':
46-
return (
47-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="20" height="20">
48-
<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" />
49-
</svg>
50-
);
51-
case 'rating':
52-
return (
53-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="20" height="20">
54-
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
55-
</svg>
56-
);
57-
case 'system':
58-
return (
59-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="20" height="20">
60-
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" />
61-
</svg>
62-
);
63-
default:
64-
return (
65-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="20" height="20">
66-
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-13h2v6h-2zm0 8h2v2h-2z" />
67-
</svg>
68-
);
34+
case 'trade': return '[T]';
35+
case 'offer': return '[O]';
36+
case 'dispute': return '[D]';
37+
case 'rating': return '[R]';
38+
case 'system': return '[S]';
39+
default: return '[A]';
6940
}
7041
};
71-
72-
return (
73-
<div className="activity-feed card">
74-
<div className="card-header">
75-
<h3 className="card-title">Recent Activity</h3>
76-
</div>
77-
78-
{activities.length === 0 ? (
79-
<div className="no-activities">
80-
No recent activity to display.
81-
</div>
82-
) : (
83-
<div className="activity-list">
84-
{activities.map((activity) => (
85-
<div key={activity.id} className={`activity-item activity-${activity.type}`}>
86-
<div className="activity-icon">
87-
{getActivityIcon(activity.type)}
88-
</div>
89-
90-
<div className="activity-content">
91-
<div className="activity-message">
92-
{activity.message}
93-
</div>
94-
95-
<div className="activity-meta">
96-
<span className="activity-time">
97-
{formatRelativeTime(activity.timestamp)}
98-
</span>
99-
100-
{activity.relatedId && (
101-
<span className="activity-id">
102-
ID: {activity.relatedId}
103-
</span>
104-
)}
105-
</div>
106-
</div>
107-
108-
{activity.actionable && (
109-
<div className="activity-action">
110-
<button
111-
className="button button-sm button-outline"
112-
onClick={() => window.location.href = activity.actionLink}
113-
>
114-
{activity.actionText}
115-
</button>
116-
</div>
117-
)}
118-
</div>
119-
))}
120-
</div>
121-
)}
122-
123-
{activities.length > 0 && (
124-
<div className="activity-feed-footer">
125-
<button className="button button-ghost button-sm">
126-
View All Activity
127-
</button>
42+
43+
// Prepare activity data for PropertyValueTable
44+
const activityData = activities.map((activity) => ({
45+
property: `${getActivityIcon(activity.type)} ${activity.type.toUpperCase()}`,
46+
value: (
47+
<div className="activity-summary">
48+
<div className="activity-message">{activity.message}</div>
49+
<div className="activity-meta">
50+
<span className="activity-time">{formatRelativeTime(activity.timestamp)}</span>
51+
{activity.relatedId && (
52+
<span className="activity-id">ID: {activity.relatedId}</span>
53+
)}
54+
{activity.actionable && (
55+
<button
56+
className="activity-action-btn"
57+
onClick={() => window.location.href = activity.actionLink}
58+
>
59+
{activity.actionText}
60+
</button>
61+
)}
12862
</div>
129-
)}
63+
</div>
64+
),
65+
className: `activity-row activity-${activity.type}`,
66+
description: activity.actionable ? `Action available: ${activity.actionText}` : null,
67+
}));
68+
69+
const activityActions = (
70+
<button className="button button-ghost button-sm">
71+
VIEW ALL ACTIVITY
72+
</button>
73+
);
74+
75+
return (
76+
<div className="activity-feed">
77+
<PropertyValueTable
78+
title="Recent Activity"
79+
data={activityData}
80+
actions={activityActions}
81+
className="activity-table"
82+
/>
13083
</div>
13184
);
13285
};

0 commit comments

Comments
 (0)