Skip to content

Commit 1e184eb

Browse files
authored
Collins (#333)
* refactor: update project components and API for voting functionality - Adjust layout and styling in ProjectsPage and ProjectCard components. - Enhance ProjectSidebar to include crowdfund data and voting logic. - Implement new API methods for voting, retrieving votes, and removing votes. - Update types for vote handling in the API. - Clean up unused code and improve responsiveness across components. * chore: update project dependencies and enhance project details layout * feat: added static api for staging * fix: made few changes * fix: minor changes * feat: chaged test data * fix: minor fixes * refactor: update project components and improve functionality * feat: file clean up * feat: added extra validation * feat: integrate wallet protection and validation across components * feat: enhance profile components and add activity tracking - Refactor ProfileData to use ProfileDataClient for improved user data display. - Introduce ActivityFeed and ActivityTab components for tracking user activities. - Implement filtering and sorting functionality in the new ProjectsTab and FilterControls components. - Add modal support for displaying followers and following lists. - Create reusable TeamList component for displaying team members across various sections. - Integrate mock data for testing and development purposes. - Update UserStats to include clickable follower and following counts for better user interaction.
1 parent 6ea3ee7 commit 1e184eb

21 files changed

Lines changed: 1649 additions & 144 deletions

app/(landing)/me/profile-data.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { getMe } from '@/lib/api/auth';
22
import { auth } from '@/auth';
3-
import ProfileOverview from '@/components/profile/ProfileOverview';
3+
import ProfileDataClient from '@/components/profile/ProfileDataClient';
44

55
export async function ProfileData() {
66
const session = await auth();
@@ -17,9 +17,9 @@ export async function ProfileData() {
1717
try {
1818
const userData = await getMe(session.user.accessToken);
1919
return (
20-
<ProfileOverview
21-
username={session.user.username || 'me'}
20+
<ProfileDataClient
2221
user={userData}
22+
username={session.user.username || 'me'}
2323
/>
2424
);
2525
} catch (error) {

components/ProjectCard.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ interface ProjectCardProps {
2020
onValidationClick?: () => void;
2121
onVoteClick?: () => void;
2222
className?: string;
23+
isFullWidth?: boolean;
2324
}
2425

2526
const ProjectCard: React.FC<ProjectCardProps> = memo(
@@ -28,6 +29,7 @@ const ProjectCard: React.FC<ProjectCardProps> = memo(
2829
creatorName = 'Creator Name',
2930
creatorAvatar,
3031
className = '',
32+
isFullWidth = false,
3133
}) => {
3234
const cardRef = useRef<HTMLDivElement>(null);
3335
const imageRef = useRef<HTMLDivElement>(null);
@@ -160,7 +162,7 @@ const ProjectCard: React.FC<ProjectCardProps> = memo(
160162
return (
161163
<div
162164
ref={cardRef}
163-
className={`group mx-auto w-full max-w-[397px] cursor-pointer overflow-hidden rounded-[8px] border border-[#2B2B2B] bg-[#030303] p-3 will-change-transform sm:p-5 ${className}`}
165+
className={`group mx-auto ${isFullWidth ? 'w-full' : 'w-full max-w-[397px]'} cursor-pointer overflow-hidden rounded-[8px] border border-[#2B2B2B] bg-[#030303] p-3 will-change-transform sm:p-5 ${className}`}
164166
style={{ transform: 'translateZ(0)' }}
165167
>
166168
<div className='mb-3 flex items-center justify-between sm:mb-4'>
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
'use client';
2+
3+
import { useState } from 'react';
4+
import { ChevronDown } from 'lucide-react';
5+
import Image from 'next/image';
6+
7+
interface ActivityItem {
8+
id: string;
9+
type: 'comment' | 'back' | 'add' | 'submit' | 'apply' | 'reply';
10+
description: string;
11+
projectName?: string;
12+
amount?: string;
13+
hackathonName?: string;
14+
grantName?: string;
15+
timestamp: string;
16+
emoji?: string;
17+
image?: string;
18+
}
19+
20+
const mockActivities: ActivityItem[] = [
21+
// TODAY
22+
{
23+
id: '1',
24+
type: 'comment',
25+
description: 'Commented on project:',
26+
projectName: 'Bitmed',
27+
emoji: '💡🌍',
28+
timestamp: '2 mins ago',
29+
},
30+
{
31+
id: '2',
32+
type: 'back',
33+
description: 'Backed project:',
34+
projectName: 'SolarPay',
35+
amount: '$250 USDC',
36+
timestamp: '10 mins ago',
37+
},
38+
{
39+
id: '3',
40+
type: 'add',
41+
description: 'Added new project:',
42+
projectName: 'EduChain',
43+
timestamp: '30 mins ago',
44+
},
45+
{
46+
id: '4',
47+
type: 'submit',
48+
description: 'Submitted project:',
49+
projectName: 'EduChain',
50+
hackathonName: 'DeFi Innovators Hackathon',
51+
timestamp: '11 h',
52+
},
53+
// YESTERDAY
54+
{
55+
id: '5',
56+
type: 'comment',
57+
description: 'Commented on project:',
58+
projectName: 'EduChain',
59+
emoji: '📱',
60+
timestamp: 'Yesterday',
61+
},
62+
{
63+
id: '6',
64+
type: 'back',
65+
description: 'Backed project:',
66+
projectName: 'AgriChain',
67+
amount: '$75 USDC',
68+
timestamp: 'Yesterday',
69+
},
70+
// THIS WEEK
71+
{
72+
id: '7',
73+
type: 'apply',
74+
description: 'Applied for grant:',
75+
grantName: 'Open Finance Fund',
76+
timestamp: '2d',
77+
},
78+
{
79+
id: '8',
80+
type: 'submit',
81+
description: 'Submitted project to hackathon:',
82+
hackathonName: 'Global Impact Hack 2025',
83+
timestamp: '2d',
84+
},
85+
{
86+
id: '9',
87+
type: 'reply',
88+
description: 'Replied to comment on',
89+
projectName: 'SolarPay',
90+
emoji: '🔜',
91+
timestamp: '3d',
92+
},
93+
{
94+
id: '10',
95+
type: 'back',
96+
description: 'Backed project:',
97+
projectName: 'GreenGrid',
98+
amount: '$500 USDC',
99+
timestamp: '3d',
100+
},
101+
];
102+
103+
const getActivityDescription = (activity: ActivityItem) => {
104+
let description = activity.description;
105+
106+
if (activity.projectName) {
107+
description += ` ${activity.projectName}`;
108+
}
109+
110+
if (
111+
activity.description.includes('to hackathon:') &&
112+
activity.hackathonName
113+
) {
114+
description += ` ${activity.hackathonName}`;
115+
}
116+
117+
if (activity.amount) {
118+
description += ` — Funded ${activity.amount}`;
119+
}
120+
121+
if (activity.emoji) {
122+
description += ` ${activity.emoji}`;
123+
}
124+
125+
return description;
126+
};
127+
128+
interface ActivityFeedProps {
129+
filter: string;
130+
}
131+
132+
export default function ActivityFeed({ filter }: ActivityFeedProps) {
133+
const [showAll, setShowAll] = useState(false);
134+
135+
const todayActivities = mockActivities.slice(0, 4);
136+
const yesterdayActivities = mockActivities.slice(4, 6);
137+
const weekActivities = mockActivities.slice(6, 10);
138+
139+
// Filter activities based on selected filter
140+
const getFilteredActivities = () => {
141+
switch (filter) {
142+
case 'Today':
143+
return [{ title: 'TODAY', activities: todayActivities }];
144+
case 'Yesterday':
145+
return [{ title: 'YESTERDAY', activities: yesterdayActivities }];
146+
case 'This Week':
147+
return [
148+
{ title: 'TODAY', activities: todayActivities },
149+
{ title: 'YESTERDAY', activities: yesterdayActivities },
150+
{ title: 'THIS WEEK', activities: weekActivities },
151+
];
152+
case 'This Month':
153+
return [
154+
{ title: 'TODAY', activities: todayActivities },
155+
{ title: 'YESTERDAY', activities: yesterdayActivities },
156+
{ title: 'THIS WEEK', activities: weekActivities },
157+
];
158+
case 'This Year':
159+
return [
160+
{ title: 'TODAY', activities: todayActivities },
161+
{ title: 'YESTERDAY', activities: yesterdayActivities },
162+
{ title: 'THIS WEEK', activities: weekActivities },
163+
];
164+
case 'All Time':
165+
return [
166+
{ title: 'TODAY', activities: todayActivities },
167+
{ title: 'YESTERDAY', activities: yesterdayActivities },
168+
{ title: 'THIS WEEK', activities: weekActivities },
169+
];
170+
default: // 'All'
171+
return [
172+
{ title: 'TODAY', activities: todayActivities },
173+
{ title: 'YESTERDAY', activities: yesterdayActivities },
174+
{ title: 'THIS WEEK', activities: weekActivities },
175+
];
176+
}
177+
};
178+
179+
const groupedActivities = getFilteredActivities();
180+
181+
return (
182+
<div className='space-y-6'>
183+
{groupedActivities.map((group, groupIndex) => (
184+
<div key={groupIndex}>
185+
<h3 className='mb-4 text-sm text-white'>{group.title}</h3>
186+
<div className='ml-5 space-y-4'>
187+
{group.activities.map(activity => (
188+
<div key={activity.id} className='flex items-start gap-3'>
189+
<Image
190+
src={activity.image || '/avatar.png'}
191+
alt={activity.projectName || 'Project Image'}
192+
width={20}
193+
height={20}
194+
className='h-8 w-8 rounded-full'
195+
/>
196+
<div className='flex-1'>
197+
<p className='text-sm text-white'>
198+
{getActivityDescription(activity)}
199+
</p>
200+
<p className='mt-1 text-xs text-gray-400'>
201+
{activity.timestamp}
202+
</p>
203+
</div>
204+
</div>
205+
))}
206+
</div>
207+
</div>
208+
))}
209+
210+
{showAll && filter === 'All' && (
211+
<div>
212+
<h3 className='mb-4 text-sm text-white'>EARLIER</h3>
213+
<div className='ml-5 space-y-4'>
214+
{mockActivities.slice(10).map(activity => (
215+
<div key={activity.id} className='flex items-start gap-3'>
216+
<Image
217+
src={activity.image || '/admin.png'}
218+
alt={activity.projectName || 'Project Image'}
219+
width={20}
220+
height={20}
221+
className='h-8 w-8 rounded-full'
222+
/>
223+
<div className='flex-1'>
224+
<p className='text-sm text-white'>
225+
{getActivityDescription(activity)}
226+
</p>
227+
<p className='mt-1 text-xs text-gray-400'>
228+
{activity.timestamp}
229+
</p>
230+
</div>
231+
</div>
232+
))}
233+
</div>
234+
</div>
235+
)}
236+
237+
{filter === 'All' && (
238+
<div className='flex justify-center pt-4'>
239+
<button
240+
onClick={() => setShowAll(!showAll)}
241+
className='flex items-center gap-2 text-gray-400 transition-colors hover:text-white'
242+
>
243+
{showAll ? 'Show Less' : 'Show More'}
244+
<ChevronDown
245+
className={`h-4 w-4 transition-transform ${showAll ? 'rotate-180' : ''}`}
246+
/>
247+
</button>
248+
</div>
249+
)}
250+
</div>
251+
);
252+
}

0 commit comments

Comments
 (0)