+
{stats.followers}
Followers
diff --git a/components/profile/mockData.ts b/components/profile/mockData.ts
new file mode 100644
index 000000000..732209450
--- /dev/null
+++ b/components/profile/mockData.ts
@@ -0,0 +1,344 @@
+import { Project } from '@/types/project';
+import { TeamMember } from '@/components/ui/TeamList';
+
+export const mockFollowers: TeamMember[] = [
+ {
+ id: '1',
+ name: 'Alice Johnson',
+ role: 'OWNER',
+ avatar: '/avatar.png',
+ username: 'alice_j',
+ joinedAt: '2024-01-15',
+ },
+ {
+ id: '2',
+ name: 'Bob Smith',
+ role: 'MEMBER',
+ avatar: '/admin.png',
+ username: 'bob_smith',
+ joinedAt: '2024-02-01',
+ },
+ {
+ id: '3',
+ name: 'Carol Davis',
+ role: 'MEMBER',
+ avatar: '/avatar.png',
+ username: 'carol_d',
+ joinedAt: '2024-02-10',
+ },
+ {
+ id: '4',
+ name: 'David Wilson',
+ role: 'MEMBER',
+ avatar: '/admin.png',
+ username: 'david_w',
+ joinedAt: '2024-02-15',
+ },
+ {
+ id: '5',
+ name: 'Eva Brown',
+ role: 'MEMBER',
+ avatar: '/avatar.png',
+ username: 'eva_b',
+ joinedAt: '2024-02-20',
+ },
+ {
+ id: '6',
+ name: 'Frank Miller',
+ role: 'MEMBER',
+ avatar: '/admin.png',
+ username: 'frank_m',
+ joinedAt: '2024-02-25',
+ },
+];
+
+export const mockProjects: Project[] = [
+ // Projects
+ {
+ id: '1',
+ name: 'Bitmed',
+ description:
+ 'To build a secure, transparent, and trusted digital health ecosystem powered by Sonic blockchain for 280M lives in Indonesia.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['Validation', 'Health'],
+ category: 'healthcare',
+ type: 'crowdfunding',
+ amount: 50000,
+ status: 'funding',
+ createdAt: '2024-01-01',
+ updatedAt: '2024-01-15',
+ owner: 'creator1',
+ ownerName: 'Creator Name',
+ ownerUsername: 'creator_name',
+ ownerAvatar: '/avatar.png',
+ },
+ {
+ id: '2',
+ name: 'SolarPay',
+ description:
+ 'Revolutionary solar energy payment system using blockchain technology to enable peer-to-peer energy trading in developing countries.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['Funding', 'Energy'],
+ category: 'environment',
+ type: 'crowdfunding',
+ amount: 75000,
+ status: 'funding',
+ createdAt: '2024-01-05',
+ updatedAt: '2024-01-20',
+ owner: 'creator2',
+ ownerName: 'Creator Name',
+ ownerUsername: 'creator_name',
+ ownerAvatar: '/admin.png',
+ },
+ {
+ id: '3',
+ name: 'EduChain',
+ description:
+ 'Decentralized learning platform for remote students with blockchain-verified certificates and micro-credentials.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['Education', 'Certification'],
+ category: 'education',
+ type: 'crowdfunding',
+ amount: 30000,
+ status: 'funding',
+ createdAt: '2024-01-10',
+ updatedAt: '2024-01-25',
+ owner: 'creator3',
+ ownerName: 'Creator Name',
+ ownerUsername: 'creator_name',
+ ownerAvatar: '/avatar.png',
+ },
+ {
+ id: '4',
+ name: 'AgriChain',
+ description:
+ 'Blockchain-based supply chain tracking for agricultural products ensuring food safety and transparency from farm to table.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['Agriculture', 'Supply Chain'],
+ category: 'social_impact',
+ type: 'crowdfunding',
+ amount: 60000,
+ status: 'funding',
+ createdAt: '2024-01-15',
+ updatedAt: '2024-01-30',
+ owner: 'creator4',
+ ownerName: 'Creator Name',
+ ownerUsername: 'creator_name',
+ ownerAvatar: '/admin.png',
+ },
+ {
+ id: '5',
+ name: 'GreenGrid',
+ description:
+ 'Smart grid infrastructure for renewable energy distribution with AI-powered optimization and blockchain-based energy credits.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['Energy', 'AI'],
+ category: 'environment',
+ type: 'crowdfunding',
+ amount: 100000,
+ status: 'funding',
+ createdAt: '2024-01-20',
+ updatedAt: '2024-02-05',
+ owner: 'creator5',
+ ownerName: 'Creator Name',
+ ownerUsername: 'creator_name',
+ ownerAvatar: '/avatar.png',
+ },
+ // Hackathons
+ {
+ id: '6',
+ name: 'DeFi Innovators Hackathon',
+ description:
+ 'Build the next generation of decentralized finance applications with focus on cross-chain interoperability and user experience.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['DeFi', 'Cross-chain'],
+ category: 'defi',
+ type: 'hackathon',
+ amount: 25000,
+ status: 'funding',
+ createdAt: '2024-02-01',
+ updatedAt: '2024-02-10',
+ owner: 'hackathon1',
+ ownerName: 'Hackathon Organizer',
+ ownerUsername: 'hackathon_org',
+ ownerAvatar: '/admin.png',
+ },
+ {
+ id: '7',
+ name: 'Global Impact Hack 2025',
+ description:
+ 'Sustainable technology solutions for climate change, healthcare, and education with focus on real-world impact and scalability.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['Climate', 'Impact'],
+ category: 'social_impact',
+ type: 'hackathon',
+ amount: 50000,
+ status: 'funding',
+ createdAt: '2024-02-05',
+ updatedAt: '2024-02-15',
+ owner: 'hackathon2',
+ ownerName: 'Hackathon Organizer',
+ ownerUsername: 'hackathon_org',
+ ownerAvatar: '/avatar.png',
+ },
+ {
+ id: '8',
+ name: 'Web3 Gaming Championship',
+ description:
+ 'Create immersive gaming experiences using blockchain technology, NFTs, and play-to-earn mechanics.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['Gaming', 'NFTs'],
+ category: 'web3',
+ type: 'hackathon',
+ amount: 40000,
+ status: 'funding',
+ createdAt: '2024-02-10',
+ updatedAt: '2024-02-20',
+ owner: 'hackathon3',
+ ownerName: 'Hackathon Organizer',
+ ownerUsername: 'hackathon_org',
+ ownerAvatar: '/admin.png',
+ },
+ {
+ id: '9',
+ name: 'AI & Blockchain Fusion',
+ description:
+ 'Integrate artificial intelligence with blockchain technology to create innovative solutions for data privacy and smart contracts.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['AI', 'Privacy'],
+ category: 'technology',
+ type: 'hackathon',
+ amount: 35000,
+ status: 'funding',
+ createdAt: '2024-02-15',
+ updatedAt: '2024-02-25',
+ owner: 'hackathon4',
+ ownerName: 'Hackathon Organizer',
+ ownerUsername: 'hackathon_org',
+ ownerAvatar: '/avatar.png',
+ },
+ // Grants
+ {
+ id: '10',
+ name: 'Open Finance Fund',
+ description:
+ 'Supporting open-source financial infrastructure projects that promote financial inclusion and transparency.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['Open Source', 'Finance'],
+ category: 'defi',
+ type: 'grant',
+ amount: 100000,
+ status: 'funding',
+ createdAt: '2024-03-01',
+ updatedAt: '2024-03-10',
+ owner: 'grant1',
+ ownerName: 'Grant Provider',
+ ownerUsername: 'grant_provider',
+ ownerAvatar: '/admin.png',
+ },
+ {
+ id: '11',
+ name: 'Climate Tech Initiative',
+ description:
+ 'Funding innovative climate technology solutions including carbon tracking, renewable energy, and environmental monitoring.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['Climate', 'Tech'],
+ category: 'environment',
+ type: 'grant',
+ amount: 150000,
+ status: 'funding',
+ createdAt: '2024-03-05',
+ updatedAt: '2024-03-15',
+ owner: 'grant2',
+ ownerName: 'Grant Provider',
+ ownerUsername: 'grant_provider',
+ ownerAvatar: '/avatar.png',
+ },
+ {
+ id: '12',
+ name: 'Healthcare Innovation Grant',
+ description:
+ 'Supporting blockchain-based healthcare solutions for patient data management, telemedicine, and medical research.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['Healthcare', 'Research'],
+ category: 'healthcare',
+ type: 'grant',
+ amount: 80000,
+ status: 'funding',
+ createdAt: '2024-03-10',
+ updatedAt: '2024-03-20',
+ owner: 'grant3',
+ ownerName: 'Grant Provider',
+ ownerUsername: 'grant_provider',
+ ownerAvatar: '/admin.png',
+ },
+ {
+ id: '13',
+ name: 'Education for All',
+ description:
+ 'Democratizing education through blockchain technology, providing access to quality education resources worldwide.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['Education', 'Accessibility'],
+ category: 'education',
+ type: 'grant',
+ amount: 120000,
+ status: 'funding',
+ createdAt: '2024-03-15',
+ updatedAt: '2024-03-25',
+ owner: 'grant4',
+ ownerName: 'Grant Provider',
+ ownerUsername: 'grant_provider',
+ ownerAvatar: '/avatar.png',
+ },
+ {
+ id: '14',
+ name: 'DAO Governance Research',
+ description:
+ 'Advancing decentralized autonomous organization governance models and voting mechanisms for better community decision-making.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['DAO', 'Governance'],
+ category: 'dao',
+ type: 'grant',
+ amount: 60000,
+ status: 'funding',
+ createdAt: '2024-03-20',
+ updatedAt: '2024-03-30',
+ owner: 'grant5',
+ ownerName: 'Grant Provider',
+ ownerUsername: 'grant_provider',
+ ownerAvatar: '/admin.png',
+ },
+ {
+ id: '15',
+ name: 'NFT Art Revolution',
+ description:
+ 'Supporting digital artists and creators in the NFT space with tools, platforms, and marketplace development.',
+ image: '/bitmed.png',
+ link: '#',
+ tags: ['NFT', 'Art'],
+ category: 'nft',
+ type: 'grant',
+ amount: 70000,
+ status: 'funding',
+ createdAt: '2024-03-25',
+ updatedAt: '2024-04-05',
+ owner: 'grant6',
+ ownerName: 'Grant Provider',
+ ownerUsername: 'grant_provider',
+ ownerAvatar: '/admin.png',
+ },
+];
diff --git a/components/profile/useProjectFilters.ts b/components/profile/useProjectFilters.ts
new file mode 100644
index 000000000..885c598b0
--- /dev/null
+++ b/components/profile/useProjectFilters.ts
@@ -0,0 +1,82 @@
+'use client';
+
+import { useState } from 'react';
+import { Project } from '@/types/project';
+
+export function useProjectFilters(projects: Project[]) {
+ const [activeTab, setActiveTab] = useState('Projects');
+ const [sortFilter, setSortFilter] = useState('Default');
+ const [statusFilter, setStatusFilter] = useState('Status');
+ const [categoryFilter, setCategoryFilter] = useState('Category');
+
+ const getFilteredProjects = () => {
+ if (!projects) return [];
+
+ let filteredProjects = [...projects];
+
+ // Filter by tab type
+ if (activeTab === 'Projects') {
+ filteredProjects = filteredProjects.filter(
+ project => project.type === 'crowdfunding'
+ );
+ } else if (activeTab === 'Hackathons') {
+ filteredProjects = filteredProjects.filter(
+ project => project.type === 'hackathon'
+ );
+ } else if (activeTab === 'Grants') {
+ filteredProjects = filteredProjects.filter(
+ project => project.type === 'grant'
+ );
+ }
+
+ // Filter by status
+ if (statusFilter !== 'Status') {
+ filteredProjects = filteredProjects.filter(
+ project => project.status === statusFilter.toLowerCase()
+ );
+ }
+
+ // Filter by category
+ if (categoryFilter !== 'Category') {
+ const categoryMap: { [key: string]: string } = {
+ Health: 'healthcare',
+ Finance: 'defi',
+ Environment: 'environment',
+ Education: 'education',
+ Technology: 'technology',
+ };
+ const mappedCategory =
+ categoryMap[categoryFilter] || categoryFilter.toLowerCase();
+ filteredProjects = filteredProjects.filter(
+ project => project.category === mappedCategory
+ );
+ }
+
+ // Sort projects
+ if (sortFilter === 'Newest') {
+ filteredProjects.sort(
+ (a, b) =>
+ new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
+ );
+ } else if (sortFilter === 'Oldest') {
+ filteredProjects.sort(
+ (a, b) =>
+ new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
+ );
+ }
+
+ return filteredProjects;
+ };
+
+ return {
+ activeTab,
+ setActiveTab,
+ sortFilter,
+ setSortFilter,
+ statusFilter,
+ setStatusFilter,
+ categoryFilter,
+ setCategoryFilter,
+ getFilteredProjects,
+ };
+}
diff --git a/components/project-details/project-team.tsx b/components/project-details/project-team.tsx
index d4009c610..5a8a603b8 100644
--- a/components/project-details/project-team.tsx
+++ b/components/project-details/project-team.tsx
@@ -2,21 +2,12 @@
import React from 'react';
import { CrowdfundingProject } from '@/lib/api/types';
-import Image from 'next/image';
+import { TeamList, TeamMember } from '@/components/ui/TeamList';
interface ProjectTeamProps {
project: CrowdfundingProject;
}
-interface TeamMember {
- id: string;
- name: string;
- role: 'OWNER' | 'MEMBER';
- avatar?: string;
- joinedAt?: string;
- username?: string;
-}
-
export function ProjectTeam({ project }: ProjectTeamProps) {
// Create team members from real project data
const teamMembers: TeamMember[] = React.useMemo(() => {
@@ -54,121 +45,16 @@ export function ProjectTeam({ project }: ProjectTeamProps) {
return members;
}, [project.creator, project.team]);
- const getRoleColor = (role: 'OWNER' | 'MEMBER') => {
- return role === 'OWNER' ? 'text-[#DBF936]' : 'text-[#B5B5B5]';
- };
-
- const handleMemberClick = () => {
- // TODO: Navigate to member profile or show member details
- // Handle member click action
+ const handleMemberClick = (member: TeamMember) => {
+ window.open(`/profile/${member.username}`, '_blank');
};
- // Show empty state if no team members
- if (teamMembers.length === 0) {
- return (
-
-
-
No Team Members
-
- This project doesn't have any team members yet.
-
-
- );
- }
-
return (
-
-
- {teamMembers.map(member => (
-
-
- {/* Avatar */}
-
-
- {member.avatar ? (
-
- ) : (
-
- )}
-
- {/* Role indicator */}
- {member.role === 'OWNER' && (
-
- )}
-
-
- {/* Member Info */}
-
-
- {member.name}
-
-
-
- {member.role}
-
- {member.username && (
-
- @{member.username}
-
- )}
-
- {member.joinedAt && (
-
- Joined {new Date(member.joinedAt).toLocaleDateString()}
-
- )}
-
-
-
- {/* Chevron */}
-
-
- ))}
-
-
+
);
}
diff --git a/components/ui/TeamList.tsx b/components/ui/TeamList.tsx
new file mode 100644
index 000000000..ef16fbe6e
--- /dev/null
+++ b/components/ui/TeamList.tsx
@@ -0,0 +1,150 @@
+'use client';
+
+import React from 'react';
+import Image from 'next/image';
+
+export interface TeamMember {
+ id: string;
+ name: string;
+ role: 'OWNER' | 'MEMBER';
+ avatar?: string;
+ joinedAt?: string;
+ username?: string;
+}
+
+interface TeamListProps {
+ members: TeamMember[];
+ onMemberClick?: (member: TeamMember) => void;
+ showEmptyState?: boolean;
+ emptyStateTitle?: string;
+ emptyStateDescription?: string;
+ className?: string;
+}
+
+export function TeamList({
+ members,
+ onMemberClick,
+ showEmptyState = true,
+ emptyStateTitle = 'No Team Members',
+ emptyStateDescription = "This project doesn't have any team members yet.",
+ className = '',
+}: TeamListProps) {
+ const getRoleColor = (role: 'OWNER' | 'MEMBER') => {
+ return role === 'OWNER' ? 'text-[#DBF936]' : 'text-[#B5B5B5]';
+ };
+
+ const handleMemberClick = (member: TeamMember) => {
+ if (onMemberClick) {
+ onMemberClick(member);
+ }
+ };
+
+ // Show empty state if no team members
+ if (members.length === 0 && showEmptyState) {
+ return (
+
+
+
+ {emptyStateTitle}
+
+
{emptyStateDescription}
+
+ );
+ }
+
+ return (
+
+
+ {members.map(member => (
+
handleMemberClick(member)}
+ >
+
+ {/* Avatar */}
+
+
+ {member.avatar ? (
+
+ ) : (
+
+ )}
+
+ {/* Role indicator */}
+ {member.role === 'OWNER' && (
+
+ )}
+
+
+ {/* Member Info */}
+
+
+ {member.name}
+
+
+
+ {member.role}
+
+ {member.username && (
+
+ @{member.username}
+
+ )}
+
+ {member.joinedAt && (
+
+ Joined {new Date(member.joinedAt).toLocaleDateString()}
+
+ )}
+
+
+
+ {/* Chevron */}
+
+
+ ))}
+
+
+ );
+}
diff --git a/hooks/use-protected-action.ts b/hooks/use-protected-action.ts
index 9ac880d06..0d10b3039 100644
--- a/hooks/use-protected-action.ts
+++ b/hooks/use-protected-action.ts
@@ -68,7 +68,7 @@ export function useProtectedAction({
return false;
}
},
- [isHydrated, isConnected, publicKey, requireWallet, actionName, onSuccess]
+ [isHydrated, isConnected, publicKey, requireWallet, onSuccess]
);
const handleWalletConnectedWithRedirect = useCallback(() => {
diff --git a/lib/api/api.ts b/lib/api/api.ts
index 1af831c4d..edeb5c309 100644
--- a/lib/api/api.ts
+++ b/lib/api/api.ts
@@ -2,8 +2,8 @@ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import Cookies from 'js-cookie';
import { useAuthStore } from '@/lib/stores/auth-store';
-const API_BASE_URL = 'https://staging-api.boundlessfi.xyz/api';
-// const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL;
+// const API_BASE_URL = 'https://staging-api.boundlessfi.xyz/api';
+const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL;
if (!API_BASE_URL) {
throw new Error('NEXT_PUBLIC_API_URL environment variable is not defined');
}