diff --git a/docs/core-checklist-status.md b/docs/core-checklist-status.md index 53626db..f326b2f 100644 --- a/docs/core-checklist-status.md +++ b/docs/core-checklist-status.md @@ -31,7 +31,7 @@ Legend: 22. Text Formatting - `DONE` (bold/italic/underline/spoiler/mono/links + strikethrough + quote/code block; web composer supports keyboard shortcuts `Ctrl/Cmd+B/I/U/K`, `Ctrl/Cmd+Shift+X`, `Ctrl/Cmd+Shift+\``) 23. Groups - `DONE` (create/add/remove/invite link with role-aware moderation flows in web Chat Info and covered invite/join behavior) 24. Roles - `DONE` (owner/admin/member) -25. Admin Rights - `DONE` (delete/pin/edit info + ban/unban/member role management with role-gated UI and APIs for groups/channels) +25. Admin Rights - `DONE` (delete/pin/edit info + ban/unban/member role management with role-gated UI and APIs for groups/channels; member role no longer sees participants lists in group/channel chat info) 26. Channels - `DONE` (create/post/edit/delete/subscribe/unsubscribe with role-aware channel behavior and invite-link flows) 27. Channel Types - `DONE` (public/private) 28. Notifications - `DONE` (browser notifications + mute/settings/sound; mention override for muted chats, realtime sync for mute state, notification click deep-link (`/?chat=..&message=..`) restores chat/message focus after auth) diff --git a/web/src/components/ChatInfoPanel.tsx b/web/src/components/ChatInfoPanel.tsx index aebb4a9..fa5dfee 100644 --- a/web/src/components/ChatInfoPanel.tsx +++ b/web/src/components/ChatInfoPanel.tsx @@ -88,7 +88,8 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) { return null; }, [myRole]); const isGroupLike = chat?.type === "group" || chat?.type === "channel"; - const showMembersSection = Boolean(chat && isGroupLike && !chat.is_saved); + const canViewMembersList = Boolean(isGroupLike && (myRoleNormalized === "owner" || myRoleNormalized === "admin")); + const showMembersSection = Boolean(chat && isGroupLike && !chat.is_saved && canViewMembersList); const canManageMembers = Boolean(isGroupLike && (myRoleNormalized === "owner" || myRoleNormalized === "admin")); const canEditTitle = Boolean(isGroupLike && (myRoleNormalized === "owner" || myRoleNormalized === "admin")); const canEditChatProfile = Boolean(isGroupLike && (myRoleNormalized === "owner" || myRoleNormalized === "admin")); @@ -225,8 +226,14 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) { setCounterpartProfile(null); setCounterpartBlocked(false); } - const nextMembers = await refreshMembers(targetChatId); - const resolvedRole = String(detail.my_role ?? nextMembers.find((m) => m.user_id === me?.id)?.role ?? "").toLowerCase(); + const resolvedRole = String(detail.my_role ?? "").toLowerCase(); + const canLoadMembers = (detail.type === "group" || detail.type === "channel") && (resolvedRole === "owner" || resolvedRole === "admin"); + if (canLoadMembers) { + await refreshMembers(targetChatId); + } else { + setMembers([]); + setMemberUsers({}); + } const canLoadBans = (detail.type === "group" || detail.type === "channel") && (resolvedRole === "owner" || resolvedRole === "admin"); if (canLoadBans) { await refreshBans(targetChatId);