From 3af491f3a2d6b48e18a9fbfd061e3baedb257781 Mon Sep 17 00:00:00 2001 From: Akshay Date: Thu, 6 Nov 2025 16:02:18 +0530 Subject: [PATCH 1/3] feat(connections): Enhance connections page layout and scrolling behavior - Improve tab content scrolling with `min-h-0` and `overflow-hidden` classes - Add flex layout adjustments for better responsiveness in tab content - Wrap list content in div for consistent spacing and layout - Optimize search tab layout with flex and scrolling improvements - Ensure consistent tab content rendering and scrolling behavior --- app/protected/connections/page.tsx | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/app/protected/connections/page.tsx b/app/protected/connections/page.tsx index 540d82b0..b23cc66d 100644 --- a/app/protected/connections/page.tsx +++ b/app/protected/connections/page.tsx @@ -42,10 +42,10 @@ export default function ConnectionsPage() { {/* Main Content */} -
+
- - + + Following @@ -60,16 +60,20 @@ export default function ConnectionsPage() { - - + +
+ +
- - + +
+ +
- -
+ +
)}
- +
+ +
From cf4d6ee1b9f20f3a5841e25322d24c436a63d083 Mon Sep 17 00:00:00 2001 From: Akshay Date: Thu, 6 Nov 2025 16:16:51 +0530 Subject: [PATCH 2/3] feat(connections): Add mutual connections display for user profiles - Implement MutualConnections component to show shared connections - Add new service method in connectionService to fetch mutual connections - Integrate mutual connections display in UserCard and UserProfileModal - Enhance user connection information with dynamic avatar stack and text description - Implement fallback and styling for mutual connections display --- components/connections/MutualConnections.tsx | 103 +++++++++++++++++++ components/connections/UserCard.tsx | 3 + components/connections/UserProfileModal.tsx | 4 + lib/services/connectionService.ts | 55 ++++++++++ 4 files changed, 165 insertions(+) create mode 100644 components/connections/MutualConnections.tsx diff --git a/components/connections/MutualConnections.tsx b/components/connections/MutualConnections.tsx new file mode 100644 index 00000000..f14c5217 --- /dev/null +++ b/components/connections/MutualConnections.tsx @@ -0,0 +1,103 @@ +'use client' + +import React, { useEffect, useState } from 'react' +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' +import { Users } from 'lucide-react' +import { connectionService } from '@/lib/services/connectionService' + +interface MutualConnectionsProps { + userId: string + className?: string +} + +interface MutualUser { + id: string + first_name: string | null + last_name: string | null + username: string + avatar_url: string | null +} + +export function MutualConnections({ userId, className = '' }: MutualConnectionsProps) { + const [mutualData, setMutualData] = useState<{ + count: number + users: MutualUser[] + }>({ count: 0, users: [] }) + const [loading, setLoading] = useState(true) + + useEffect(() => { + const loadMutualConnections = async () => { + try { + const data = await connectionService.getMutualConnections(userId) + setMutualData(data) + } catch (error) { + console.error('Error loading mutual connections:', error) + } finally { + setLoading(false) + } + } + + loadMutualConnections() + }, [userId]) + + if (loading || mutualData.count === 0) { + return null + } + + const displayUsers = mutualData.users.slice(0, 3) + const remainingCount = mutualData.count - displayUsers.length + + const getName = (user: MutualUser) => { + if (user.first_name && user.last_name) { + return `${user.first_name} ${user.last_name}` + } + return user.username + } + + const getInitials = (user: MutualUser) => { + if (user.first_name && user.last_name) { + return `${user.first_name[0]}${user.last_name[0]}`.toUpperCase() + } + return user.username.slice(0, 2).toUpperCase() + } + + return ( +
+ +
+ {/* Avatar stack */} +
+ {displayUsers.map((user) => ( + + {user.avatar_url && } + + {getInitials(user)} + + + ))} +
+ + {/* Text */} + + Connected with{' '} + + {displayUsers[0] && getName(displayUsers[0])} + + {displayUsers.length > 1 && ( + <> + {' '}and{' '} + + {remainingCount > 0 + ? `${displayUsers.length - 1 + remainingCount} others` + : displayUsers.length === 2 + ? getName(displayUsers[1]) + : `${displayUsers.length - 1} others` + } + + + )} + +
+
+ ) +} diff --git a/components/connections/UserCard.tsx b/components/connections/UserCard.tsx index db624cd6..0391cd08 100644 --- a/components/connections/UserCard.tsx +++ b/components/connections/UserCard.tsx @@ -9,6 +9,7 @@ import { connectionService } from '@/lib/services/connectionService' import { conversationService } from '@/lib/services/conversationService' import { useRouter } from 'next/navigation' import { UserProfileModal } from './UserProfileModal' +import { MutualConnections } from './MutualConnections' interface UserCardProps { user: { @@ -147,6 +148,8 @@ export function UserCard({ user, connectionStatus, onConnectionChange, showMessa {user.bio && (

{user.bio}

)} + {/* Mutual Connections */} +
diff --git a/components/connections/UserProfileModal.tsx b/components/connections/UserProfileModal.tsx index 7319f374..05210230 100644 --- a/components/connections/UserProfileModal.tsx +++ b/components/connections/UserProfileModal.tsx @@ -29,6 +29,7 @@ import { connectionService } from '@/lib/services/connectionService' import { conversationService } from '@/lib/services/conversationService' import { useRouter } from 'next/navigation' import Link from 'next/link' +import { MutualConnections } from './MutualConnections' interface UserProfileModalProps { userId: string @@ -214,6 +215,9 @@ export function UserProfileModal({ )}
+ {/* Mutual Connections */} + + {/* Action Buttons */}
{connectionStatus.isMutual && ( diff --git a/lib/services/connectionService.ts b/lib/services/connectionService.ts index 75b0a262..5b152269 100644 --- a/lib/services/connectionService.ts +++ b/lib/services/connectionService.ts @@ -179,6 +179,61 @@ export class ConnectionService { return { isFollowing, isFollower, isMutual } } + + // Get mutual connections between current user and another user + async getMutualConnections(userId: string): Promise<{ + count: number + users: Array<{ + id: string + first_name: string | null + last_name: string | null + username: string + avatar_url: string | null + }> + }> { + const supabase = this.getSupabaseClient() + const { data: { user } } = await supabase.auth.getUser() + + if (!user) { + return { count: 0, users: [] } + } + + // Get users that both current user and target user follow + const { data: currentUserFollowing } = await supabase + .from('user_connections') + .select('following_id') + .eq('follower_id', user.id) + + const { data: targetUserFollowing } = await supabase + .from('user_connections') + .select('following_id') + .eq('follower_id', userId) + + if (!currentUserFollowing || !targetUserFollowing) { + return { count: 0, users: [] } + } + + // Find mutual following + const currentFollowingIds = new Set(currentUserFollowing.map(c => c.following_id)) + const mutualIds = targetUserFollowing + .map(c => c.following_id) + .filter(id => currentFollowingIds.has(id) && id !== user.id && id !== userId) + + if (mutualIds.length === 0) { + return { count: 0, users: [] } + } + + // Get profile info for first 3 mutual connections + const { data: profiles } = await supabase + .from('profiles') + .select('id, first_name, last_name, username, avatar_url') + .in('id', mutualIds.slice(0, 3)) + + return { + count: mutualIds.length, + users: profiles || [] + } + } } export const connectionService = new ConnectionService() From 909da90ee84e27b1671b7d4eae5cf50237a12f04 Mon Sep 17 00:00:00 2001 From: Akshay Date: Thu, 6 Nov 2025 16:29:20 +0530 Subject: [PATCH 3/3] feat(connections): Enhance UserCard with responsive layout and improved UX - Refactor UserCard component for better mobile and desktop responsiveness - Add dynamic layout adjustments for user information and action buttons - Improve interactive elements with hover and focus states - Optimize badge and button display for different screen sizes - Add flex-shrink and truncation to prevent layout breaking - Enhance accessibility with better aria labels and button interactions - Adjust spacing and positioning of user profile elements - Improve visual hierarchy and readability of user information --- components/connections/UserCard.tsx | 174 ++++++++++++++-------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/components/connections/UserCard.tsx b/components/connections/UserCard.tsx index 0391cd08..ff295170 100644 --- a/components/connections/UserCard.tsx +++ b/components/connections/UserCard.tsx @@ -92,7 +92,7 @@ export function UserCard({ user, connectionStatus, onConnectionChange, showMessa return ( <> -
+
{/* Clickable Avatar */}
-
-
- {/* Clickable Name */} + {/* User Info Section */} +
+ {/* Clickable Name */} + +
-
- - {localStatus?.isMutual && ( - - - Connected - - )} - {!localStatus?.isMutual && localStatus?.isFollowing && ( - - - Following - - )} - {!localStatus?.isMutual && localStatus?.isFollower && ( - - - Follows you - - )} -
- {user.bio && ( -

{user.bio}

+ {localStatus?.isMutual && ( + + + Connected + + )} + {!localStatus?.isMutual && localStatus?.isFollowing && ( + + + Following + + )} + {!localStatus?.isMutual && localStatus?.isFollower && ( + + + Follows you + )} - {/* Mutual Connections */} -
+ {user.bio && ( +

{user.bio}

+ )} + {/* Mutual Connections */} + +
-
- {/* View Profile Button */} + {/* Action Buttons - Stack on mobile, inline on desktop */} +
+ {/* View Profile Button */} + + + {showMessageButton && localStatus?.isMutual && ( - - {showMessageButton && localStatus?.isMutual && ( - - )} - - {localStatus?.isFollowing ? ( - - ) : ( - - )} -
+ )} + + {localStatus?.isFollowing ? ( + + ) : ( + + )}