fix(web): unify mic/send button and restore scroll-down
Some checks failed
CI / test (push) Failing after 20s
Some checks failed
CI / test (push) Failing after 20s
- show one action button in composer: mic when empty, send when text exists - add floating scroll-to-bottom button in message list - exclude non-text/media messages from Chat Info links list to avoid duplicates
This commit is contained in:
@@ -61,9 +61,20 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) {
|
||||
}
|
||||
return members.find((m) => m.user_id === me?.id)?.role;
|
||||
}, [chat?.my_role, members, me?.id]);
|
||||
const myRoleNormalized = useMemo(() => {
|
||||
if (!myRole) {
|
||||
return null;
|
||||
}
|
||||
const role = String(myRole).toLowerCase();
|
||||
if (role === "owner" || role === "admin" || role === "member") {
|
||||
return role;
|
||||
}
|
||||
return null;
|
||||
}, [myRole]);
|
||||
const isGroupLike = chat?.type === "group" || chat?.type === "channel";
|
||||
const showMembersSection = Boolean(chat && isGroupLike && !chat.is_saved);
|
||||
const canManageMembers = Boolean(isGroupLike && (myRole === "owner" || myRole === "admin"));
|
||||
const canManageMembers = Boolean(isGroupLike && (myRoleNormalized === "owner" || myRoleNormalized === "admin"));
|
||||
const canEditTitle = Boolean(isGroupLike && (myRoleNormalized === "owner" || myRoleNormalized === "admin"));
|
||||
const photoAttachments = useMemo(() => attachments.filter((item) => item.file_type.startsWith("image/")).sort((a, b) => b.id - a.id), [attachments]);
|
||||
const videoAttachments = useMemo(() => attachments.filter((item) => item.file_type.startsWith("video/")).sort((a, b) => b.id - a.id), [attachments]);
|
||||
const voiceAttachments = useMemo(() => attachments.filter((item) => item.message_type === "voice").sort((a, b) => b.id - a.id), [attachments]);
|
||||
@@ -259,7 +270,7 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) {
|
||||
</button>
|
||||
</div>
|
||||
<p className="mb-2 text-xs text-slate-300">{muted ? "Chat notifications are muted." : "Chat notifications are enabled."}</p>
|
||||
{isGroupLike ? (
|
||||
{isGroupLike && canEditTitle ? (
|
||||
<>
|
||||
<p className="mt-2 text-xs text-slate-400">Title</p>
|
||||
<input
|
||||
@@ -321,7 +332,7 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) {
|
||||
const canOpenMemberMenu =
|
||||
canManageMembers &&
|
||||
!isSelf &&
|
||||
(myRole === "owner" || (myRole === "admin" && member.role === "member"));
|
||||
(myRoleNormalized === "owner" || (myRoleNormalized === "admin" && member.role === "member"));
|
||||
return (
|
||||
<button
|
||||
className="block w-full rounded border border-slate-700/60 bg-slate-900/60 p-2 text-left hover:bg-slate-800/70"
|
||||
@@ -652,7 +663,7 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) {
|
||||
style={{ left: memberCtx.x, top: memberCtx.y }}
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
>
|
||||
{myRole === "owner" && memberCtx.member.role === "member" ? (
|
||||
{myRoleNormalized === "owner" && memberCtx.member.role === "member" ? (
|
||||
<button
|
||||
className="block w-full rounded px-2 py-1.5 text-left text-sm hover:bg-slate-800"
|
||||
onClick={async () => {
|
||||
@@ -670,7 +681,7 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) {
|
||||
Make admin
|
||||
</button>
|
||||
) : null}
|
||||
{myRole === "owner" && memberCtx.member.role === "admin" ? (
|
||||
{myRoleNormalized === "owner" && memberCtx.member.role === "admin" ? (
|
||||
<button
|
||||
className="block w-full rounded px-2 py-1.5 text-left text-sm hover:bg-slate-800"
|
||||
onClick={async () => {
|
||||
@@ -688,7 +699,7 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) {
|
||||
Remove admin rights
|
||||
</button>
|
||||
) : null}
|
||||
{myRole === "owner" && memberCtx.member.role !== "owner" ? (
|
||||
{myRoleNormalized === "owner" && memberCtx.member.role !== "owner" ? (
|
||||
<button
|
||||
className="block w-full rounded px-2 py-1.5 text-left text-sm hover:bg-slate-800"
|
||||
onClick={async () => {
|
||||
@@ -706,7 +717,7 @@ export function ChatInfoPanel({ chatId, open, onClose }: Props) {
|
||||
Transfer ownership
|
||||
</button>
|
||||
) : null}
|
||||
{(myRole === "owner" || (myRole === "admin" && memberCtx.member.role === "member")) ? (
|
||||
{(myRoleNormalized === "owner" || (myRoleNormalized === "admin" && memberCtx.member.role === "member")) ? (
|
||||
<button
|
||||
className="block w-full rounded px-2 py-1.5 text-left text-sm text-red-300 hover:bg-slate-800"
|
||||
onClick={async () => {
|
||||
@@ -869,7 +880,7 @@ function extractLinkItems(messages: Message[]): Array<{ url: string; messageId:
|
||||
const seen = new Set<string>();
|
||||
const regex = /\bhttps?:\/\/[^\s<>"')]+/gi;
|
||||
for (const message of messages) {
|
||||
if (!message.text) {
|
||||
if (message.type !== "text" || !message.text) {
|
||||
continue;
|
||||
}
|
||||
const links = message.text.match(regex) ?? [];
|
||||
|
||||
Reference in New Issue
Block a user