import { FC, ReactElement, useState, useMemo, useCallback } from 'react'; import ModalTeamDetail from './_components/modal-team-detail-new'; import SubmissionModal from './_components/submission-modal'; import { BackofficeWrapper, DataTable, } from '@imphnen-frontend-service/ui/organisms'; import { ColumnDef } from '@tanstack/react-table'; import { Button } from '@imphnen-frontend-service/ui/atoms'; import { cn } from '@imphnen-frontend-service/utils'; import { EditOutlined, TeamOutlined, SearchOutlined, FilterOutlined, PlusOutlined, UserOutlined, ArrowRightOutlined, } from '@ant-design/icons'; // Define interface outside component interface TeamMember { id: string; joined_at: string; role: 'leader' | 'member'; status: 'pending' | 'accepted' | 'rejected'; team_id: string; user: { avatar?: string; bio?: string; created_at: string; email: string; fullname: string; id: string; is_active: boolean; location: string; phone_number?: string; skills: string[]; updated_at: string; }; user_id: string; } interface TeamType { id: string; name: string; description?: string; city: string; banner?: string; logo?: string; visibility: 'public' | 'private'; member_count: number; has_submission: boolean; created_at: string; updated_at: string; leader_id: string; members: TeamMember[]; } // Move mock data outside component to prevent recreation const cities = ['Jakarta', 'Bandung', 'Surabaya', 'Medan', 'Yogyakarta']; const teamNames = [ 'Innovators', 'Hackers', 'Builders', 'Creators', 'Pioneers', 'Developers', 'Engineers', 'Coders', 'Tech Stars', 'Digital Wizards', ]; const descriptions = [ 'Building innovative solutions for modern problems with cutting-edge technology', 'Passionate developers creating the next generation of web applications', 'Focused on sustainable tech solutions that make a positive impact', 'Experienced team working on scalable fintech innovations', 'Creative minds developing user-centric mobile applications', 'Full-stack developers building comprehensive business solutions', 'AI enthusiasts creating intelligent automation tools', 'Open source advocates building community-driven platforms', ]; const skills = [ 'Frontend Developer', 'Backend Developer', 'Full Stack Developer', 'DevOps Engineer', 'UI/UX Designer', 'Product Manager', 'Data Scientist', 'Mobile Developer', ]; const generateMembers = ( count: number, teamId: string, leaderId: string ): TeamMember[] => { return Array.from({ length: count }, (_, i) => { const isLeader = i === 0; const memberId = isLeader ? leaderId : `user-${teamId}-${i}`; return { id: `member-${teamId}-${i}`, joined_at: new Date( Date.now() - (count - i) * 86400000 * Math.random() * 5 ).toISOString(), role: isLeader ? 'leader' : 'member', status: Math.random() > 0.8 ? 'pending' : 'accepted', team_id: teamId, user: { id: memberId, avatar: Math.random() > 0.6 ? `https://ui-avatars.com/api/?name=${encodeURIComponent( `User ${i}` )}` : undefined, bio: Math.random() > 0.5 ? `Passionate ${skills[ Math.floor(Math.random() * skills.length) ].toLowerCase()} with ${ Math.floor(Math.random() * 8) + 1 }+ years experience` : undefined, created_at: new Date( Date.now() - Math.random() * 365 * 86400000 ).toISOString(), email: `user${i}.team${teamId}@example.com`, fullname: `${ ['Ahmad', 'Sofia', 'Budi', 'Sari', 'Rizki', 'Maya', 'Andi', 'Dina'][ Math.floor(Math.random() * 8) ] } ${ [ 'Wijuana', 'Santoso', 'Pratama', 'Dewi', 'Nugroho', 'Sari', 'Putra', 'Lestari', ][Math.floor(Math.random() * 8)] }`, is_active: true, location: cities[Math.floor(Math.random() * cities.length)], phone_number: Math.random() > 0.7 ? `+62${Math.floor(Math.random() * 9000000000) + 1000000000}` : undefined, skills: skills.slice(0, Math.floor(Math.random() * 3) + 1), updated_at: new Date().toISOString(), }, user_id: memberId, }; }); }; const mockData: TeamType[] = Array.from({ length: 50 }, (_, i) => { const teamId = `team-${String(i + 1).padStart(3, '0')}`; const memberCount = Math.floor(Math.random() * 5) + 1; // 1-5 members const leaderId = `leader-${teamId}`; const members = generateMembers(memberCount, teamId, leaderId); return { id: teamId, name: `Team ${teamNames[i % teamNames.length]} ${ Math.floor(i / teamNames.length) + 1 }`, description: i % 4 === 0 ? undefined : descriptions[i % descriptions.length], city: cities[i % cities.length], banner: i % 3 === 0 ? undefined : `https://picsum.photos/600/200?random=${i}`, // 3:1 aspect ratio logo: i % 4 === 0 ? undefined : `https://ui-avatars.com/api/?name=${encodeURIComponent( teamNames[i % teamNames.length] )}&background=random&size=120`, visibility: i % 4 === 0 ? 'private' : 'public', member_count: memberCount, has_submission: i % 3 !== 0, created_at: new Date( Date.now() - i * 86400000 * (Math.random() * 15 + 1) ).toISOString(), updated_at: new Date().toISOString(), leader_id: leaderId, members: members, }; }); export const HackathonTeamsPage: FC = (): ReactElement => { const [showDetailModal, setShowDetailModal] = useState(false); const [showNewTeamModal, setShowNewTeamModal] = useState(false); const [showSubmissionModal, setShowSubmissionModal] = useState(false); const [selectedTeam, setSelectedTeam] = useState(null); const [selectedSubmissionTeam, setSelectedSubmissionTeam] = useState(null); const [globalFilter, setGlobalFilter] = useState(''); // Advanced filtering states const [visibilityFilter, setVisibilityFilter] = useState('all'); const [cityFilter, setCityFilter] = useState('all'); const [submissionFilter, setSubmissionFilter] = useState('all'); const [memberCountFilter, setMemberCountFilter] = useState('all'); // Constants const pageSize = 10; // Memoize the callback to prevent recreation const handleShowDetailModal = useCallback((team: TeamType) => { setSelectedTeam(team); setShowDetailModal(true); }, []); const handleCloseDetailModal = useCallback(() => { setShowDetailModal(false); setSelectedTeam(null); }, []); const handleShowNewTeamModal = useCallback(() => { setShowNewTeamModal(true); }, []); const handleCloseNewTeamModal = useCallback(() => { setShowNewTeamModal(false); }, []); const handleShowSubmissionModal = useCallback((team: TeamType) => { setSelectedSubmissionTeam(team); setShowSubmissionModal(true); }, []); const handleCloseSubmissionModal = useCallback(() => { setShowSubmissionModal(false); setSelectedSubmissionTeam(null); }, []); // Filter data based on current filter states const filteredData = useMemo(() => { return mockData.filter((team) => { // Global search filter if (globalFilter) { const searchTerm = globalFilter.toLowerCase(); const leaderName = team.members.find((m) => m.role === 'leader')?.user.fullname || ''; const memberNames = team.members.map((m) => m.user.fullname).join(' '); if ( !team.name.toLowerCase().includes(searchTerm) && !team.city.toLowerCase().includes(searchTerm) && !team.description?.toLowerCase().includes(searchTerm) && !leaderName.toLowerCase().includes(searchTerm) && !memberNames.toLowerCase().includes(searchTerm) ) { return false; } } // Visibility filter if (visibilityFilter !== 'all' && team.visibility !== visibilityFilter) { return false; } // City filter if (cityFilter !== 'all' && team.city !== cityFilter) { return false; } // Submission filter if (submissionFilter !== 'all') { const hasSubmission = submissionFilter === 'submitted'; if (team.has_submission !== hasSubmission) return false; } // Member count filter if (memberCountFilter !== 'all') { const count = parseInt(memberCountFilter); if (team.member_count !== count) return false; } return true; }); }, [ globalFilter, visibilityFilter, cityFilter, submissionFilter, memberCountFilter, ]); // Memoize columns to prevent recreation on every render const columns: ColumnDef[] = useMemo( () => [ { accessorKey: 'name', header: 'Team', cell: ({ row }) => { const team = row.original; return (
{/* Team Logo */}
{team.logo ? ( {team.name} ) : ( )}
{/* Team Name & Description */}

{team.name}

); }, enableSorting: true, }, { accessorKey: 'city', header: 'City', cell: ({ row }) => ( {row.original.city} ), enableSorting: true, }, { accessorKey: 'visibility', header: 'Visibility', cell: ({ row }) => { const isPublic = row.original.visibility === 'public'; return ( {isPublic ? 'Public' : 'Private'} ); }, enableSorting: true, }, { accessorKey: 'member_count', header: 'Members', cell: ({ row }) => (
{row.original.member_count}
), enableSorting: true, }, { id: 'leader', header: 'Leader', cell: ({ row }) => { const leader = row.original.members.find( (m) => m.role === 'leader' )?.user; return leader ? (
{leader.fullname}
{leader.email}
) : ( No leader ); }, enableSorting: false, }, { accessorKey: 'has_submission', header: 'Submission', cell: ({ row }) => { const hasSubmission = row.original.has_submission; return (
{hasSubmission ? 'Submitted' : 'Not Submitted'} {hasSubmission && ( )}
); }, enableSorting: true, sortingFn: (rowA, rowB) => { const aSubmission = rowA.original.has_submission; const bSubmission = rowB.original.has_submission; if (aSubmission && !bSubmission) return -1; if (!aSubmission && bSubmission) return 1; return 0; }, }, { accessorKey: 'created_at', header: 'Created', cell: ({ row }) => ( {new Date(row.original.created_at).toLocaleDateString('en-UK', { year: 'numeric', month: 'short', day: 'numeric', })} ), enableSorting: true, sortingFn: 'datetime', }, { id: 'actions', header: 'Actions', meta: { cellClassName: cn('w-48') }, cell: ({ row }) => (
), enableSorting: false, }, ], [handleShowDetailModal, handleShowSubmissionModal] ); return (

Team Management

{/* Filters and actions */}
{/* Left side - Search & filters */}
{/* Search bar */}
setGlobalFilter(e.target.value)} />
{/* Visibility Filter */}
{/* City Filter */}
{/* Member Count Filter */}
{/* Submission Filter */}
{/* Right side - Add Team Button */}
{/* Active filters display */} {(visibilityFilter !== 'all' || cityFilter !== 'all' || submissionFilter !== 'all' || memberCountFilter !== 'all') && (
Active filters: {/* Visibility filter badge */} {visibilityFilter !== 'all' && ( Visibility: {visibilityFilter} )} {/* City filter badge */} {cityFilter !== 'all' && ( City: {cityFilter} )} {/* Member count filter badge */} {memberCountFilter !== 'all' && ( Members: {memberCountFilter} )} {/* Submission filter badge */} {submissionFilter !== 'all' && ( Submission: {submissionFilter} )} {/* Clear all filters */}
)} {/* Pagination-aware results display */} {filteredData.length > 0 && (
Showing {Math.min(pageSize, filteredData.length)} of{' '} {filteredData.length} teams {filteredData.length > pageSize}
)} {/* Table */}
{/* Modals component */} {/* New Team Modal */} {/* Submission Modal */} {selectedSubmissionTeam && ( )}
); }; export default HackathonTeamsPage;