mirror of
https://github.com/nextcloud/spreed.git
synced 2025-12-18 05:20:50 +01:00
feat(schedule): action to post scheduled messages immediately
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
This commit is contained in:
parent
0066ae52f6
commit
aadada5948
3 changed files with 76 additions and 8 deletions
|
|
@ -5,9 +5,11 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { BigIntChatMessage } from '../../../../../types/index.ts'
|
import type { BigIntChatMessage } from '../../../../../types/index.ts'
|
||||||
|
import type { RawTemporaryMessagePayload } from '../../../../../utils/prepareTemporaryMessage.ts'
|
||||||
|
|
||||||
import { t } from '@nextcloud/l10n'
|
import { t } from '@nextcloud/l10n'
|
||||||
import { computed, inject, ref } from 'vue'
|
import { computed, inject, ref } from 'vue'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
|
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
|
||||||
import NcActionInput from '@nextcloud/vue/components/NcActionInput'
|
import NcActionInput from '@nextcloud/vue/components/NcActionInput'
|
||||||
import NcActions from '@nextcloud/vue/components/NcActions'
|
import NcActions from '@nextcloud/vue/components/NcActions'
|
||||||
|
|
@ -20,8 +22,11 @@ import IconCalendarClockOutline from 'vue-material-design-icons/CalendarClockOut
|
||||||
import IconCheck from 'vue-material-design-icons/Check.vue'
|
import IconCheck from 'vue-material-design-icons/Check.vue'
|
||||||
import IconDotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'
|
import IconDotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'
|
||||||
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'
|
import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue'
|
||||||
|
import IconSend from 'vue-material-design-icons/Send.vue'
|
||||||
import IconSendVariantClock from 'vue-material-design-icons/SendVariantClock.vue'
|
import IconSendVariantClock from 'vue-material-design-icons/SendVariantClock.vue'
|
||||||
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
|
import IconTrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
|
||||||
|
import { useTemporaryMessage } from '../../../../../composables/useTemporaryMessage.ts'
|
||||||
|
import { EventBus } from '../../../../../services/EventBus.ts'
|
||||||
import { useChatExtrasStore } from '../../../../../stores/chatExtras.ts'
|
import { useChatExtrasStore } from '../../../../../stores/chatExtras.ts'
|
||||||
import { convertToUnix, formatDateTime } from '../../../../../utils/formattedTime.ts'
|
import { convertToUnix, formatDateTime } from '../../../../../utils/formattedTime.ts'
|
||||||
import { getCustomDateOptions } from '../../../../../utils/getCustomDateOptions.ts'
|
import { getCustomDateOptions } from '../../../../../utils/getCustomDateOptions.ts'
|
||||||
|
|
@ -39,6 +44,9 @@ const emit = defineEmits<{
|
||||||
const getMessagesListScroller = inject('getMessagesListScroller', () => undefined)
|
const getMessagesListScroller = inject('getMessagesListScroller', () => undefined)
|
||||||
|
|
||||||
const chatExtrasStore = useChatExtrasStore()
|
const chatExtrasStore = useChatExtrasStore()
|
||||||
|
const vuexStore = useStore()
|
||||||
|
|
||||||
|
const { createTemporaryMessage } = useTemporaryMessage()
|
||||||
|
|
||||||
const submenu = ref<'schedule' | null>(null)
|
const submenu = ref<'schedule' | null>(null)
|
||||||
const customScheduleTimestamp = ref(new Date(new Date().setHours(new Date().getHours() + 1, 0, 0, 0)))
|
const customScheduleTimestamp = ref(new Date(new Date().setHours(new Date().getHours() + 1, 0, 0, 0)))
|
||||||
|
|
@ -73,6 +81,40 @@ async function handleDelete() {
|
||||||
await chatExtrasStore.deleteScheduledMessage(props.message.token, props.message.id)
|
await chatExtrasStore.deleteScheduledMessage(props.message.token, props.message.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the scheduled message
|
||||||
|
*/
|
||||||
|
async function handleSubmit() {
|
||||||
|
const temporaryMessagePayload: RawTemporaryMessagePayload = {
|
||||||
|
message: props.message.message,
|
||||||
|
token: props.message.token,
|
||||||
|
silent: props.message.silent,
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((props.message.threadId ?? 0) > 0) {
|
||||||
|
temporaryMessagePayload.threadId = props.message.threadId
|
||||||
|
temporaryMessagePayload.isThread = true
|
||||||
|
}
|
||||||
|
if (props.message.parent?.id && !props.message.parent.deleted) {
|
||||||
|
temporaryMessagePayload.parent = props.message.parent
|
||||||
|
}
|
||||||
|
if (props.message.threadId === -1) {
|
||||||
|
// Substitute thread title with message text, if missing
|
||||||
|
temporaryMessagePayload.threadTitle = props.message.threadTitle
|
||||||
|
temporaryMessagePayload.threadReplies = 0
|
||||||
|
temporaryMessagePayload.isThread = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const temporaryMessage = createTemporaryMessage(temporaryMessagePayload)
|
||||||
|
|
||||||
|
// FIXME: quite scheduled messages view
|
||||||
|
// FIXME: Scroll to bottom after sending the scheduled message
|
||||||
|
EventBus.emit('scroll-chat-to-bottom', { smooth: true, force: true })
|
||||||
|
|
||||||
|
await vuexStore.dispatch('postNewMessage', { token: props.message.token, temporaryMessage })
|
||||||
|
await chatExtrasStore.deleteScheduledMessage(props.message.token, props.message.id)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle action menu open state
|
* Toggle action menu open state
|
||||||
*/
|
*/
|
||||||
|
|
@ -130,7 +172,6 @@ function onMenuClose() {
|
||||||
|
|
||||||
<NcActionButton
|
<NcActionButton
|
||||||
key="edit-message"
|
key="edit-message"
|
||||||
:aria-label="t('spreed', 'Edit message')"
|
|
||||||
close-after-click
|
close-after-click
|
||||||
@click.stop="handleEdit">
|
@click.stop="handleEdit">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
|
|
@ -147,6 +188,18 @@ function onMenuClose() {
|
||||||
</template>
|
</template>
|
||||||
{{ t('spreed', 'Delete') }}
|
{{ t('spreed', 'Delete') }}
|
||||||
</NcActionButton>
|
</NcActionButton>
|
||||||
|
|
||||||
|
<NcActionSeparator />
|
||||||
|
|
||||||
|
<NcActionButton
|
||||||
|
key="send-message"
|
||||||
|
close-after-click
|
||||||
|
@click.stop="handleSubmit">
|
||||||
|
<template #icon>
|
||||||
|
<IconSend :size="20" />
|
||||||
|
</template>
|
||||||
|
{{ t('spreed', 'Send message now') }}
|
||||||
|
</NcActionButton>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="submenu === 'schedule'">
|
<template v-else-if="submenu === 'schedule'">
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { PrepareTemporaryMessagePayload } from '../utils/prepareTemporaryMessage.ts'
|
import type { RawTemporaryMessagePayload } from '../utils/prepareTemporaryMessage.ts'
|
||||||
|
|
||||||
import { useActorStore } from '../stores/actor.ts'
|
import { useActorStore } from '../stores/actor.ts'
|
||||||
import { prepareTemporaryMessage } from '../utils/prepareTemporaryMessage.ts'
|
import { prepareTemporaryMessage } from '../utils/prepareTemporaryMessage.ts'
|
||||||
|
|
@ -17,7 +17,7 @@ export function useTemporaryMessage() {
|
||||||
/**
|
/**
|
||||||
* @param payload payload for generating a temporary message
|
* @param payload payload for generating a temporary message
|
||||||
*/
|
*/
|
||||||
function createTemporaryMessage(payload: PrepareTemporaryMessagePayload) {
|
function createTemporaryMessage(payload: RawTemporaryMessagePayload) {
|
||||||
return prepareTemporaryMessage({
|
return prepareTemporaryMessage({
|
||||||
...payload,
|
...payload,
|
||||||
actorId: actorStore.actorId ?? '',
|
actorId: actorStore.actorId ?? '',
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,21 @@ import SHA256 from 'crypto-js/sha256.js'
|
||||||
import { MESSAGE } from '../constants.ts'
|
import { MESSAGE } from '../constants.ts'
|
||||||
import { hasTalkFeature } from '../services/CapabilitiesManager.ts'
|
import { hasTalkFeature } from '../services/CapabilitiesManager.ts'
|
||||||
|
|
||||||
|
export type RawTemporaryMessagePayload = Pick<ChatMessage,
|
||||||
|
| 'message'
|
||||||
|
| 'token'
|
||||||
|
| 'silent'
|
||||||
|
> & Partial<Pick<ChatMessage,
|
||||||
|
| 'actorId'
|
||||||
|
| 'actorType'
|
||||||
|
| 'actorDisplayName'
|
||||||
|
| 'threadId'
|
||||||
|
| 'isThread'
|
||||||
|
| 'threadTitle'
|
||||||
|
| 'threadReplies'
|
||||||
|
| 'parent'
|
||||||
|
>>
|
||||||
|
|
||||||
export type PrepareTemporaryMessagePayload = Pick<ChatMessage,
|
export type PrepareTemporaryMessagePayload = Pick<ChatMessage,
|
||||||
| 'message'
|
| 'message'
|
||||||
| 'token'
|
| 'token'
|
||||||
|
|
@ -21,13 +36,13 @@ export type PrepareTemporaryMessagePayload = Pick<ChatMessage,
|
||||||
| 'isThread'
|
| 'isThread'
|
||||||
| 'threadTitle'
|
| 'threadTitle'
|
||||||
| 'threadReplies'
|
| 'threadReplies'
|
||||||
|
| 'parent'
|
||||||
> & {
|
> & {
|
||||||
uploadId: string
|
uploadId?: string
|
||||||
index: number
|
index?: number
|
||||||
file: File & { newName?: string }
|
file?: File & { newName?: string }
|
||||||
localUrl: string
|
localUrl?: string
|
||||||
messageType?: typeof MESSAGE.TYPE['VOICE_MESSAGE' | 'COMMENT']
|
messageType?: typeof MESSAGE.TYPE['VOICE_MESSAGE' | 'COMMENT']
|
||||||
parent: Omit<ChatMessage, 'parent'>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue