Fixed message deletion error and layout changes for the message input box.

This commit is contained in:
2026-09-30 09:19:36 +03:30
parent 58e89246d9
commit 298b3316b4
7 changed files with 176 additions and 76 deletions
+103 -46
View File
@@ -46,7 +46,7 @@ const recording = ref(false);
const recordSecs = ref(0);
const lightboxUrl = ref('');
const fileInputEl = ref<HTMLInputElement | null>(null);
const draftInputEl = ref<HTMLInputElement | null>(null);
const draftInputEl = ref<HTMLTextAreaElement | null>(null);
const emojiOpen = ref(false);
const editingMessageId = ref<string | null>(null);
const msgMenu = ref<{ id: string; x: number; y: number } | null>(null);
@@ -194,11 +194,19 @@ function selectedMessages(): ChatMessage[] {
async function deleteSelected() {
if (!activeRoom.value || !selectedIds.value.length) return;
const n = selectedIds.value.length;
if (!window.confirm(n > 1 ? `${n} پیام حذف شوند؟` : 'این پیام حذف شود؟')) return;
const ids = [...selectedIds.value];
const list = selectedMessages();
if (!list.length) return;
const mineCount = list.filter((m) => isMineMessage(m)).length;
const otherCount = list.length - mineCount;
const parts: string[] = [];
if (mineCount) parts.push(`${mineCount} پیام خودتان برای همه`);
if (otherCount) parts.push(`${otherCount} پیام دریافتی فقط برای شما`);
if (!window.confirm(`حذف شود؟\n${parts.join('\n')}`)) return;
try {
await deleteMessages(activeRoom.value.externalRoomId, ids);
await deleteMessages(
activeRoom.value.externalRoomId,
list.map((m) => ({ id: m.id, forEveryone: isMineMessage(m) })),
);
exitSelectMode();
} catch (e) {
error.value = e instanceof Error ? e.message : 'حذف پیام ناموفق بود.';
@@ -266,15 +274,49 @@ function startEditMessage(msg: ChatMessage) {
async function confirmDeleteMessage(msg: ChatMessage) {
msgMenu.value = null;
if (!activeRoom.value || msg.optimistic || msg.deleted) return;
if (!window.confirm('این پیام برای همه حذف شود؟')) return;
const mine = isMineMessage(msg);
const ok = window.confirm(
mine
? 'این پیام برای همه حذف شود؟'
: 'این پیام فقط برای شما حذف شود؟ (برای طرف مقابل باقی می‌ماند)',
);
if (!ok) return;
try {
await deleteMessage(activeRoom.value.externalRoomId, msg.id);
await deleteMessage(activeRoom.value.externalRoomId, msg.id, {
forEveryone: mine,
});
if (editingMessageId.value === msg.id) cancelEdit();
} catch (e) {
error.value = e instanceof Error ? e.message : 'حذف پیام ناموفق بود.';
}
}
function onComposerKeydown(event: KeyboardEvent) {
if (event.key !== 'Enter') return;
if (event.ctrlKey || event.metaKey) {
// Ctrl/Cmd+Enter → newline
event.preventDefault();
const el = draftInputEl.value;
if (!el) {
draft.value += '\n';
return;
}
const start = el.selectionStart ?? draft.value.length;
const end = el.selectionEnd ?? start;
const next = draft.value.slice(0, start) + '\n' + draft.value.slice(end);
draft.value = next;
nextTick(() => {
const pos = start + 1;
el.focus();
el.setSelectionRange(pos, pos);
});
return;
}
if (event.shiftKey) return;
event.preventDefault();
void submitMessage();
}
function openMsgMenu(msg: ChatMessage, event: MouseEvent | TouchEvent) {
if (msg.deleted || msg.optimistic) return;
if (selectMode.value) {
@@ -966,38 +1008,6 @@ onUnmounted(() => {
accept="image/*,video/*,audio/*,.pdf,.doc,.docx,.xls,.xlsx,.zip,.rar,.txt"
@change="onFilePicked"
/>
<button
type="button"
class="tool-btn attach-btn"
title="پیوست"
:disabled="sending || recording || Boolean(editingMessageId)"
@click="fileInputEl?.click()"
>
<UiIcon name="plus" :size="20" />
</button>
<div class="input-shell">
<button
type="button"
class="emoji-toggle"
title="ایموجی"
:class="{ on: emojiOpen }"
:disabled="sending || recording"
@click="emojiOpen = !emojiOpen"
>
😊
</button>
<input
ref="draftInputEl"
v-model="draft"
type="text"
class="composer-input"
:placeholder="editingMessageId ? 'ویرایش پیام…' : 'پیام بنویسید…'"
autocomplete="off"
enterkeyhint="send"
:disabled="sending || recording"
@focus="emojiOpen = false"
/>
</div>
<button
v-if="showMicInsteadOfSend"
type="button"
@@ -1017,6 +1027,39 @@ onUnmounted(() => {
>
<UiIcon name="send" :size="18" />
</button>
<div class="input-shell">
<textarea
ref="draftInputEl"
v-model="draft"
class="composer-input"
rows="1"
:placeholder="editingMessageId ? 'ویرایش پیام…' : 'پیام بنویسید…'"
autocomplete="off"
enterkeyhint="send"
:disabled="sending || recording"
@focus="emojiOpen = false"
@keydown="onComposerKeydown"
/>
</div>
<button
type="button"
class="emoji-toggle"
title="ایموجی"
:class="{ on: emojiOpen }"
:disabled="sending || recording"
@click="emojiOpen = !emojiOpen"
>
😊
</button>
<button
type="button"
class="tool-btn attach-btn"
title="پیوست"
:disabled="sending || recording || Boolean(editingMessageId)"
@click="fileInputEl?.click()"
>
<UiIcon name="plus" :size="20" />
</button>
</div>
</form>
@@ -1062,6 +1105,15 @@ onUnmounted(() => {
<UiIcon name="trash" :size="16" />
حذف برای همه
</button>
<button
v-else
type="button"
class="danger"
@click="confirmDeleteMessage(menuMessage()!)"
>
<UiIcon name="trash" :size="16" />
حذف فقط برای من
</button>
</div>
</template>
</section>
@@ -1604,12 +1656,11 @@ onUnmounted(() => {
flex: 1 1 auto;
min-width: 0;
display: flex;
align-items: center;
gap: 0.15rem;
align-items: flex-end;
background: #fff;
border: 1px solid #e2e8f0;
border-radius: 22px;
padding: 0.15rem 0.35rem 0.15rem 0.55rem;
padding: 0.35rem 0.75rem;
min-height: 2.75rem;
}
.composer-input {
@@ -1618,17 +1669,22 @@ onUnmounted(() => {
border: none;
outline: none;
border-radius: 18px;
padding: 0.55rem 0.35rem;
padding: 0.35rem 0;
font: inherit;
font-size: 0.95rem;
background: transparent;
resize: none;
max-height: 7.5rem;
line-height: 1.45;
field-sizing: content;
}
.emoji-toggle {
flex: 0 0 auto;
border: none;
background: transparent;
width: 2.1rem;
height: 2.1rem;
background: #fff;
border: 1px solid #e2e8f0;
width: 2.75rem;
height: 2.75rem;
border-radius: 999px;
font-size: 1.15rem;
line-height: 1;
@@ -1638,6 +1694,7 @@ onUnmounted(() => {
}
.emoji-toggle.on {
background: rgba(13, 148, 136, 0.12);
border-color: rgba(13, 148, 136, 0.35);
}
.emoji-panel {
display: grid;