feat(chat): preserve message drafts in session temp store

This commit is contained in:
2026-10-15 17:45:17 +02:00
parent e933782731
commit 697f538b6e
8 changed files with 426 additions and 16 deletions

View File

@@ -7,7 +7,7 @@ const router = useRouter()
const baseRooms = ref([]), projectRooms = ref([]), directRooms = ref([]), collaborationRooms = ref([])
const invitations = ref([]), invitationBusy = ref(''), collaborationError = ref(''), listError = ref('')
const unreadRooms = ref({}), messages = ref([]), members = ref([]), draft = ref(''), draftImage = ref(null)
const unreadRooms = ref({}), messages = ref([]), members = ref([])
const requestedRoom = () => typeof route.query.room === 'string' ? route.query.room : 'allgemein'
const activeRoomKey = ref(requestedRoom())
const loading = ref(true), roomLoading = ref(false), sending = ref(false), creating = ref(false)
@@ -48,8 +48,9 @@ const groupedRooms = computed(() => ['Räume', 'Projekte', 'Direktnachrichten',
const activeRoom = computed(() => visibleRooms.value.find(room => room.key === activeRoomKey.value) || null)
const isCollaboration = computed(() => activeRoom.value?.source === 'collaboration')
const isInternal = computed(() => activeRoom.value?.source === 'internal')
const { draft, draftImage, draftSending, clearDraft, startDraftSend, finishDraftSend } = useChatDraft(() => isInternal.value ? activeRoomKey.value : '')
function clearMessages() { messages.value = []; members.value = []; draft.value = ''; draftImage.value = null; syncAfterId = 0; roomLoading.value = false; sending.value = false }
function clearMessages() { messages.value = []; members.value = []; syncAfterId = 0; roomLoading.value = false; sending.value = false }
function mergeMessages(incoming) {
const byId = new Map(messages.value.map(message => [message.id, message]))
for (const message of incoming || []) byId.set(message.id, message)
@@ -210,14 +211,17 @@ async function respondToInvitation(id, accept) {
async function sendMessage() {
const text = draft.value.trim(), image = draftImage.value, request = selection()
if ((!text && !image) || sending.value || !isInternal.value || !activeRoom.value?.exists) return
sending.value = true; draft.value = ''
const savedDraft = startDraftSend()
if (!savedDraft) return
sending.value = true
try {
const message = await $api(nativeEndpoint(request.key, '/messages'), { method: 'POST', body: { text, ...(image ? { image } : {}) } })
clearDraft(savedDraft)
if (!currentSelection(request)) return
draftImage.value = null; mergeMessages([message]); await markRead(request); await scrollToBottom(request)
mergeMessages([message]); await markRead(request); await scrollToBottom(request)
} catch (error) {
if (currentSelection(request)) { draft.value = text; toast.add({ title: errorMessage(error), color: 'error' }) }
} finally { if (currentSelection(request)) sending.value = false }
if (currentSelection(request)) toast.add({ title: errorMessage(error), color: 'error' })
} finally { finishDraftSend(savedDraft); if (currentSelection(request)) sending.value = false }
}
async function pollMessages() {
if (pollBusy || loading.value || roomLoading.value || document.hidden || !isInternal.value || !activeRoom.value?.exists) return
@@ -386,7 +390,7 @@ onBeforeUnmount(() => {
</ChatReactions>
</div>
<ChatComposer :key="`${session}:${activeRoomKey}`" v-model="draft" v-model:image="draftImage" :busy="sending" :disabled="!activeRoom?.exists || roomLoading" @send="sendMessage" />
<ChatComposer :key="`${session}:${activeRoomKey}`" v-model="draft" v-model:image="draftImage" :busy="sending || draftSending" :disabled="!activeRoom?.exists || roomLoading" @send="sendMessage" />
</main>
<aside v-if="!isCollaboration" class="hidden min-h-0 overflow-y-auto border-l border-gray-200 p-4 lg:block">