Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/community/CommunitySettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,7 @@ function JoinRequestItem({
}

// Helper component for displaying member items
function MemberItem({ member }: { member: { pubkey: string; role: 'owner' | 'moderator' | 'member'; isOnline: boolean } }) {
function MemberItem({ member }: { member: { pubkey: string; role: 'owner' | 'moderator' | 'member'; isOnline?: boolean } }) {
const author = useAuthor(member.pubkey);
const displayName = author.data?.metadata?.name || genUserName(member.pubkey);
const avatar = author.data?.metadata?.picture;
Expand Down
75 changes: 22 additions & 53 deletions src/components/layout/MemberList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useManageMembers } from "@/hooks/useManageMembers";
import { useCurrentUser } from "@/hooks/useCurrentUser";
import { useCommunities } from "@/hooks/useCommunities";
import { useAuthorBatch } from "@/hooks/useAuthorBatch";
import { useUserStatusBatch } from "@/hooks/useUserStatusBatch";
import { genUserName } from "@/lib/genUserName";
import { Skeleton } from "@/components/ui/skeleton";
import { useToast } from "@/hooks/useToast";
Expand All @@ -25,7 +26,6 @@ interface MemberListProps {
interface MemberItemProps {
pubkey: string;
role?: 'owner' | 'moderator' | 'member';
isOnline?: boolean;
communityId: string;
canManage?: boolean;
onStartDM?: (pubkey: string) => void;
Expand All @@ -35,7 +35,7 @@ interface MemberItemProps {
authorData?: { event?: NostrEvent; metadata?: NostrMetadata };
}

function MemberItem({ pubkey, role = 'member', isOnline: _isOnline = false, communityId, canManage = false, onStartDM, onFollow, onMute, onReport, authorData }: MemberItemProps) {
function MemberItem({ pubkey, role = 'member', communityId, canManage = false, onStartDM, onFollow, onMute, onReport, authorData }: MemberItemProps) {
const metadata = authorData?.metadata;
const { removeMember, isRemovingMember } = useManageMembers();
const { toast } = useToast();
Expand Down Expand Up @@ -154,14 +154,17 @@ export function MemberList({ communityId, onNavigateToDMs }: MemberListProps) {
const { data: communities } = useCommunities();
const { user } = useCurrentUser();

// Extract all member pubkeys for batched author query
// Extract all member pubkeys for batched queries
const memberPubkeys = useMemo(() => {
return members?.map(member => member.pubkey) || [];
}, [members]);

// Batch query for all member profiles
const { data: batchedAuthors, isLoading: isLoadingAuthors } = useAuthorBatch(memberPubkeys);

// Batch query for all member statuses (simplified)
const { data: _statusMap } = useUserStatusBatch(memberPubkeys);

// Check if current user can manage members (is owner or moderator)
const canManageMembers = communityId && user ? (() => {
const community = communities?.find(c => c.id === communityId);
Expand Down Expand Up @@ -200,7 +203,7 @@ export function MemberList({ communityId, onNavigateToDMs }: MemberListProps) {
);
}

// Show members list (same for all users, regardless of management capabilities)
// Show members list (simplified without online/offline grouping)
return (
<div className="flex flex-col h-full min-h-0">
{/* Header */}
Expand All @@ -227,55 +230,21 @@ export function MemberList({ communityId, onNavigateToDMs }: MemberListProps) {
</div>
) : members && members.length > 0 ? (
<div className="space-y-0.5">
{/* Online Members */}
<div className="mb-2">
<div className="text-xs font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide px-2 py-1">
Online — {members.filter(m => m.isOnline).length}
</div>
{members
.filter(member => member.isOnline)
.map((member) => (
<MemberItem
key={member.pubkey}
pubkey={member.pubkey}
role={member.role}
isOnline={member.isOnline}
communityId={communityId}
canManage={canManageMembers}
onStartDM={handleStartDM}
onFollow={handleFollow}
onMute={handleMute}
onReport={handleReport}
authorData={batchedAuthors?.[member.pubkey]}
/>
))}
</div>

{/* Offline Members */}
{members.some(m => !m.isOnline) && (
<div>
<div className="text-xs font-semibold text-gray-700 dark:text-gray-300 uppercase tracking-wide px-2 py-1">
Offline — {members.filter(m => !m.isOnline).length}
</div>
{members
.filter(member => !member.isOnline)
.map((member) => (
<MemberItem
key={member.pubkey}
pubkey={member.pubkey}
role={member.role}
isOnline={member.isOnline}
communityId={communityId}
canManage={canManageMembers}
onStartDM={handleStartDM}
onFollow={handleFollow}
onMute={handleMute}
onReport={handleReport}
authorData={batchedAuthors?.[member.pubkey]}
/>
))}
</div>
)}
{/* All members (no online/offline grouping) */}
{members.map((member) => (
<MemberItem
key={member.pubkey}
pubkey={member.pubkey}
role={member.role}
communityId={communityId}
canManage={canManageMembers}
onStartDM={handleStartDM}
onFollow={handleFollow}
onMute={handleMute}
onReport={handleReport}
authorData={batchedAuthors?.[member.pubkey]}
/>
))}
</div>
) : (
<div className="text-center text-gray-400 py-8">
Expand Down
2 changes: 0 additions & 2 deletions src/components/members/MemberCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,6 @@ export function MemberCard({
{/* Status message */}
{(userStatus?.emoji || userStatus?.message) && (
<div className="flex items-center space-x-1 mt-1">
<span className="text-sm">🌌</span>
{userStatus.emoji && (
<span className="text-sm">{userStatus.emoji}</span>
)}
Expand Down Expand Up @@ -511,7 +510,6 @@ export function MemberCard({
{/* Status message */}
{(userStatus?.emoji || userStatus?.message) && (
<div className="flex items-center space-x-1 mt-1">
<span className="text-sm">🌌</span>
{userStatus.emoji && (
<span className="text-sm">{userStatus.emoji}</span>
)}
Expand Down
26 changes: 13 additions & 13 deletions src/components/user/ProfileModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { UserStatusDialog } from "@/components/user/UserStatusDialog";
import { EditProfileDialog } from "@/components/EditProfileDialog";
import { useCurrentUser } from "@/hooks/useCurrentUser";
import { useAuthor } from "@/hooks/useAuthor";
import { getTraditionalStatusText, useUserStatus, useUserMusicStatus } from "@/hooks/useUserStatus";
import { useUserStatus, useUserMusicStatus } from "@/hooks/useUserStatus";

import { useCommunities } from "@/hooks/useCommunities";
import { useUserMembership } from "@/hooks/useUserMembership";
Expand Down Expand Up @@ -162,34 +162,34 @@ export function ProfileModal({

// Get communities and mutual spaces
const { data: communities } = useCommunities();

// Get user's memberships using efficient batch query
const { data: userMemberships } = useUserMembership();

// Get target user's memberships using efficient batch query
const { data: targetMemberships } = useUserMembershipsByPubkey(isOwnProfile ? null : profilePubkey);

// Get user's communities based on membership status
const userCommunities = useMemo(() => {
if (!user?.pubkey || !communities || !userMemberships) return [];

// Create a set of community IDs where user is a member
const memberCommunityIds = new Set<string>();

// Add communities from membership data
userMemberships.forEach(membership => {
if (membership.status === 'owner' || membership.status === 'moderator' || membership.status === 'approved') {
memberCommunityIds.add(membership.communityId);
}
});

// Also check if user is owner/moderator from community definitions
communities.forEach(community => {
if (community.creator === user.pubkey || community.moderators.includes(user.pubkey)) {
memberCommunityIds.add(community.id);
}
});

// Filter communities where user is a member
return communities.filter(community => memberCommunityIds.has(community.id));
}, [user?.pubkey, communities, userMemberships]);
Expand All @@ -198,24 +198,24 @@ export function ProfileModal({
const targetCommunities = useMemo(() => {
if (isOwnProfile) return userCommunities;
if (!profilePubkey || !communities || !targetMemberships) return [];

// Create a set of community IDs where target user is a member
const memberCommunityIds = new Set<string>();

// Add communities from membership data
targetMemberships.forEach(membership => {
if (membership.status === 'owner' || membership.status === 'moderator' || membership.status === 'approved') {
memberCommunityIds.add(membership.communityId);
}
});

// Also check if target user is owner/moderator from community definitions
communities.forEach(community => {
if (community.creator === profilePubkey || community.moderators.includes(profilePubkey)) {
memberCommunityIds.add(community.id);
}
});

// Filter communities where target user is a member
return communities.filter(community => memberCommunityIds.has(community.id));
}, [isOwnProfile, profilePubkey, communities, targetMemberships, userCommunities]);
Expand All @@ -226,7 +226,7 @@ export function ProfileModal({

// Create a set for efficient lookup
const targetCommunityIds = new Set(targetCommunities.map(c => c.id));

return userCommunities.filter(userCommunity =>
targetCommunityIds.has(userCommunity.id)
);
Expand Down Expand Up @@ -495,7 +495,7 @@ export function ProfileModal({
>
<UserStatusIndicator pubkey={profilePubkey} />
<span>
{userStatus?.emoji ? 'Custom Status' : (getTraditionalStatusText(userStatus?.status) || 'Set Status')}
{userStatus?.emoji ? 'Custom Status' : 'Set Status'}
</span>
</Button>
</div>
Expand Down
Loading
Loading